永远的 C
10/08 24
SIGHUP    终止进程    终端线路挂断
SIGINT    终止进程    中断进程
SIGQUIT   建立CORE文件终止进程,并且生成core文件
SIGILL   建立CORE文件      非法指令
SIGTRAP  建立CORE文件      跟踪自陷
SIGBUS   建立CORE文件      总线错误
SIGSEGV  建立CORE文件      段非法错误
SIGFPE   建立CORE文件      浮点异常
SIGIOT   建立CORE文件      执行I/O自陷
SIGKILL  终止进程    杀死进程
SIGPIPE  终止进程    向一个没有读进程的管道写数据
SIGALARM  终止进程    计时器到时
SIGTERM  终止进程    软件终止信号
SIGSTOP  停止进程    非终端来的停止信号
SIGTSTP  停止进程    终端来的停止信号
SIGCONT  忽略信号    继续执行一个停止的进程
SIGURG   忽略信号    I/O紧急信号
SIGIO    忽略信号    描述符上可以进行I/O
SIGCHLD  忽略信号    当子进程停止或退出时通知父进程
SIGTTOU  停止进程    后台进程写终端
SIGTTIN  停止进程    后台进程读终端
SIGXGPU  终止进程    CPU时限超时
SIGXFSZ  终止进程    文件长度过长
SIGWINCH  忽略信号    窗口大小发生变化
SIGPROF  终止进程    统计分布图用计时器到时
SIGUSR1  终止进程    用户定义信号1
SIGUSR2  终止进程    用户定义信号2
SIGVTALRM 终止进程    虚拟计时器到时

1) SIGHUP 本信号在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控
制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端
不再关联.
2) SIGINT 程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出
3) SIGQUIT 和SIGINT类似, 但由QUIT字符(通常是Ctrl-)来控制. 进程在因收到
SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信
号.
4) SIGILL 执行了非法指令. 通常是因为可执行文件本身出现错误, 或者试图执行
数据段. 堆栈溢出时也有可能产生这个信号.
5) SIGTRAP 由断点指令或其它trap指令产生. 由debugger使用.
6) SIGABRT 程序自己发现错误并调用abort时产生.
6) SIGIOT 在PDP-11上由iot指令产生, 在其它机器上和SIGABRT一样.
7) SIGBUS 非法地址, 包括内存地址对齐(alignment)出错. eg: 访问一个四个字长
的整数, 但其地址不是4的倍数.
8) SIGFPE 在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢
出及除数为0等其它所有的算术的错误.
9) SIGKILL 用来立即结束程序的运行. 本信号不能被阻塞, 处理和忽略.
10) SIGUSR1 留给用户使用
11) SIGSEGV 试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据.
12) SIGUSR2 留给用户使用
13) SIGPIPE Broken pipe
14) SIGALRM 时钟定时信号, 计算的是实际的时间或时钟时间. alarm函数使用该
信号.
15) SIGTERM 程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和
处理. 通常用来要求程序自己正常退出. shell命令kill缺省产生这
个信号.
17) SIGCHLD 子进程结束时, 父进程会收到这个信号.
18) SIGCONT 让一个停止(stopped)的进程继续执行. 本信号不能被阻塞. 可以用
一个handler来让程序在由stopped状态变为继续执行时完成特定的
工作. 例如, 重新显示提示符
19) SIGSTOP 停止(stopped)进程的执行. 注意它和terminate以及interrupt的区别:
该进程还未结束, 只是暂停执行. 本信号不能被阻塞, 处理或忽略.
20) SIGTSTP 停止进程的运行, 但该信号可以被处理和忽略. 用户键入SUSP字符时
(通常是Ctrl-Z)发出这个信号
21) SIGTTIN 当后台作业要从用户终端读数据时, 该作业中的所有进程会收到SIGTTIN
信号. 缺省时这些进程会停止执行.
22) SIGTTOU 类似于SIGTTIN, 但在写终端(或修改终端模式)时收到.
23) SIGURG 有"紧急"数据或out-of-band数据到达socket时产生.
24) SIGXCPU 超过CPU时间资源限制. 这个限制可以由getrlimit/setrlimit来读取/
改变
25) SIGXFSZ 超过文件大小资源限制.
26) SIGVTALRM 虚拟时钟信号. 类似于SIGALRM, 但是计算的是该进程占用的CPU时间.
27) SIGPROF 类似于SIGALRM/SIGVTALRM, 但包括该进程用的CPU时间以及系统调用的
时间.
28) SIGWINCH 窗口大小改变时发出.
29) SIGIO 文件描述符准备就绪, 可以开始进行输入/输出操作.
30) SIGPWR Power failure

有两个信号可以停止进程:SIGTERM和SIGKILL。 SIGTERM比较友好,进程能捕捉这个信号,根据您的需要来关闭程序。在关闭程序之前,您可以结束打开的记录文件和完成正在做的任务。在某些情况下,假如进程正在进行作业而且不能中断,那么进程可以忽略这个SIGTERM信号。

对于SIGKILL信号,进程是不能忽略的。这是一个 “我不管您在做什么,立刻停止”的信号。假如您发送SIGKILL信号给进程,Linux就将进程停止在那里。
10/07 14
/* add include files */
#include "winsock2.h"
#include "afxmt.h"
#include "Mmsystem.h"
#include
#include
#include
#include


////////////////////////////////////////////////////////////////////////
// 传输协议根据TLV(type,length,value)协议编制
//
// TLV协议说明:
// TLV格式的数据包中类型type指明了当前包的含义,type是单一包的类型或者是嵌套包的类型;
// 长度length指明了当前包的大小,注意这个的大小包括了type、length、value三部分;
// 值value包括了该数据包的实际内容,如果是嵌套包,内容为里面各个子包的总和。
//
// 当前Type字段为signed short类型,长度为2个字节;
// Length字段为signed long 类型,长度为4个字节。
//
// 采用小端模式(little endian)发送,即数据低位存储在低地址的一种形式,
// intel公司的ix86系列芯片采用这种存储方式。
//
// 分2大类:实时车辆信息包、心跳包
// 实时车辆信息包格式:T L 通行信息子包 特写图子包 全景图子包
// 心跳包格式: T L
////////////////////////////////////////////////////////////////////////

// 定义传输包数据类型
const short TYPE_REALVEHICLE = 1101; // 实时车辆信息包
//const short TYPE_OVERTIMEVEHICLE = 1102; // 补传车辆信息包
const short TYPE_HEARTBEAT = 1111; // 心跳包
const short TYPE_TIME = 1151; // 时间包
const short TYPE_PASSINFO = 1201; // 通行信息包
const short TYPE_IMAGENEAR = 1202; // 特写图片数据包
const short TYPE_IMAGEFULL = 1203; // 全景图片数据包

const int DELAY_RECEIVEDATA = 20; // 每次接收网络数据后挂起等待时间
const int DELAY_SHUTDOWNSOCKET = 10; // 每次关闭Socket句柄后的延迟
const int DELAY_WAITSUCCESS = 10; // 等待成功延时
const int DELAY_WAITQUIT = 10; // 等待退出延时
const int DELAY_WAITSENDING = 500; // 等待本次传输完成时间
const int DELAY_HEARTBEATINTERVAL = 3000; // 心跳时间间隔
const int DELAY_INSPECT = 150; // 检查网络状态的间隔

const int LIMIT_WAITRECEIVE = 200; // 等待接收最长时间
const int LIMIT_WAITQUIT = 200; // 退出延时限制
const int LIMIT_DATAOVERTIME = 10000; // 数据超时限制(保存在发送缓存中的)
const int LIMIT_HEARTBEAT = 30000; // 心跳间隔超时限制(超出认为服务器异常)
const int LIMIT_MAXLISTENCLIENT = 10; // 最大监听客户数
const int LIMIT_DEVICEID_LENGTH = 20; // 设备编号字符串长度限制
const int LIMIT_PLATE_LENGTH = 20; // 车牌字符串长度限制
const int LIMIT_PASSTIME_LENGTH = 24; // 通行时间字符串长度限制
const int LIMIT_MINIMAGENUMBER = 1; // 最小图片数量
const int LIMIT_MAXIMAGENUMBER = 2; // 最大图片数量
const int LIMIT_MINIMAGESIZE = 1L; // 图片最小占用字节
const int LIMIT_MAXIMAGESIZE = 100L * 1024L; // 图片最大占用字节
const int LIMIT_SENDBUFFERSIZE = 201L * 1024L; // TCP包最大发送大小 201K

const int WM_VEHICLEPASS = 0x401; // 车辆经过
const int WM_TCPCONNECT = 0x402; // 建立TCP连接
const int WM_TCPDISCONNECT = 0x403; // TCP连接断开

const int VALUE_ZERO = 0; // 零值

typedef struct UDT_PassInfo
{
    DWORD dwProtocalVersion; // 协议版本
    char pchDeviceId[LIMIT_DEVICEID_LENGTH]; // 设备编号 最多20位
    int  iRoadWay; // 车道号
    char pchPlate[LIMIT_PLATE_LENGTH]; // 号牌号码
char pchPassTime[LIMIT_PASSTIME_LENGTH]; // 经过时间
int  iSpeed; // 车速
int  iSpeedLimit; // 限速
DWORD dwDeviceState; // 设备状态
int  iImageNumber; // 图片数量
DWORD dwImageNearSize; // 特写图片占用空间
DWORD dwImageFullSize; // 全景图片占用空间
}UDT_PassInfo;

const int PACKET_TYPE_LENGTH = 2; // T(类型)所占长度
const int PACKET_LENGTH_LENGTH = 4;  // L(长度)所占长度
const int PACKET_HEADER_LENGTH = 6; // 头(T+L)所占长度
const int PACKET_TIME_LENGTH = 10; // 时间包长度
const int PACKET_PASSINFO_LENGTH   = sizeof(UDT_PassInfo) + PACKET_HEADER_LENGTH; // 通行信息子包长度

typedef struct UDT_TCPCommunicationClient // 通讯控制参数结构体
{
    HWND hWndProcess; // 发送消息所需句柄
DWORD dwMsgDataReady; // 数据准备好消息 默认0x401
DWORD dwMsgConnectSuccess; // 网络连接成功消息 默认0x402
DWORD dwMsgDisconnect; // 网络断开消息 默认0x403

DWORD dwServerIp; // 服务器IP
WORD wServerPort; // 服务器监听端口
BOOL bIsDebug; // 是否开启调试模式

BOOL bConnectActive; // 网络是否处于活动状态
BOOL bThreadClientAlive; // 线程是否存活
BOOL bDataIsReady; // 数据是否准备好
BOOL bIsGetingData; // 是否正在取数据
BOOL bIsAdjustTime; // 是否校时
DWORD dwReceiveTime; // 接收到的时间 unix时间格式
DWORD dwHeartBeatTime; // 心跳时间点
DWORD dwHeartBeatCount; // 心跳次数

CWinThread* threadInspect; // 监测线程句柄
CEvent evtInspectEnd;  // 监测线程信号量(通知对应线程结束)

SOCKET sckClient; // 客户端线程通讯使用的Socket句柄
CWinThread* threadClient; // 客户端线程句柄
CEvent evtClientEnd;  // 客户端线程信号量(通知对应线程结束)
CRITICAL_SECTION ctsClient; // 客户端临界区

struct UDT_PassInfo udtPassInfo; // 车辆信息数据包(不包括图片)
BYTE pbtSendBufHeartBeat[PACKET_HEADER_LENGTH]; // 心跳包发送缓存区
BYTE pbtSendBufTime[PACKET_TIME_LENGTH]; // 时间包发送缓存区
BYTE* pbtImageNearBuf; // 特写图片数据缓存区
BYTE* pbtImageFullBuf; // 全景图片数据缓存区
}UDT_TCPCommunicationClient;

static struct UDT_TCPCommunicationClient m_udtTcpClient; // 模块级变量,控制通讯
static BOOL m_bInitSuccess = FALSE; // 初始化成功标记,除Connect函数外均需要初始化成功才能调用

int WriteToLog(int iCueNumber,TCHAR *szMsg);
int WriteToLog(TCHAR *szMsg);
int WriteBinaryFile(BYTE* pbtBuffer,DWORD dwFileSize,char *pchFileName);
int TcpReceive(SOCKET sckClient,
BYTE *pchBuffer,
int iOffset,
int iReceiveSize,
int iOverTime);
UINT TcpInspectThread(LPVOID pParam);
UINT TcpServerThread(LPVOID pParam);

/*******************************************************
int GDW_VM2003_Connect(DWORD hWnd,
DWORD dwMsgDataReady,
DWORD dwMsgConnectSuccess,
DWORD dwMsgDisconnect);
int GDW_VM2003_GetVehicleInfo(char* pchPlate,
char* pchTime,
BYTE* pbtImageBin,
BYTE* pbtImagePlate,
DWORD* dwImagePlateSize,
BYTE* pbtImageNear,
DWORD* dwImageNearSize,
BYTE* pbtImageFull,
DWORD* dwImageFullSize,
char* pchDeviceId,
int* iRoadWay,
int* iSpeed,
int* iSpeedLimit,
DWORD* dwDeviceState);
int GDW_VM2003_AdjustTime(char* pchTime);
int GDW_VM2003_Disconnect();
*******************************************************/

//
// Note!
//
//  If this DLL is dynamically linked against the MFC
//  DLLs, any functions exported from this DLL which
//  call into MFC must have the AFX_MANAGE_STATE macro
//  added at the very beginning of the function.
//
//  For example:
//
//  extern "C" BOOL PASCAL EXPORT ExportedFunction()
//  {
//   AFX_MANAGE_STATE(AfxGetStaticModuleState());
//   // normal function body here
//  }
//
//  It is very important that this macro appear in each
//  function, prior to any calls into MFC.  This means that
//  it must appear as the first statement within the
//  function, even before any object variable declarations
//  as their constructors may generate calls into the MFC
//  DLL.
//
//  Please see MFC Technical Notes 33 and 58 for additional
//  details.
//

/////////////////////////////////////////////////////////////////////////////
// CGDW_TransmitApp

BEGIN_MESSAGE_MAP(CGDW_TransmitApp, CWinApp)
//{{AFX_MSG_MAP(CGDW_TransmitApp)
  // NOTE - the ClassWizard will add and remove mapping macros here.
  //    DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CGDW_TransmitApp construction

CGDW_TransmitApp::CGDW_TransmitApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}

/////////////////////////////////////////////////////////////////////////////
// The one and only CGDW_TransmitApp object

CGDW_TransmitApp theApp;

/************************************************************************
Function int WriteToLog:
    write text message to file
Input:
int iCueNumber 指示信息:一般为返回值、错误号
TCHAR *szMsg 文本字符串
OutPut:

return:
    If no error occurs, returns zero,other returns no zero;
Update:
    Version       Date           Author        Description
    1.0           2008-03-19     Shi Mingjie   Create
************************************************************************/
int WriteToLog(int iCueNumber,TCHAR *szMsg)
{
int    i = 0;
int    iLastSperate = 0;
TCHAR  szCurPath[272];
HANDLE hWndFile;
WIN32_FIND_DATA fileFind;
FILE   *fp;
SYSTEMTIME lpSystemTime;
  
GetModuleFileName(GetModuleHandle(NULL),szCurPath,256);

for (i=0; i<256; i++)
{
  if (szCurPath[i] == '\\')
  {
   iLastSperate = i;
  }
  else if(szCurPath[i] == '\0')
  {
   break;
  }
}

if (iLastSperate > 0 && i < 256)
{
  szCurPath[iLastSperate] = '\0';
}
else
{
  return -1;
}

strcat(szCurPath,"\\Tcp_Client.evt");

GetLocalTime(&lpSystemTime);

hWndFile = FindFirstFile(szCurPath,&fileFind);
FindClose(hWndFile);

if (INVALID_HANDLE_VALUE == hWndFile)
{
  if ((fp = fopen(szCurPath,"w")) == NULL)
  {
   return -2;
  }
  fprintf(fp,"%04d-%02d-%02d %02d:%02d:%02d:%03d  Event:%06d  %s\n",
          lpSystemTime.wYear,lpSystemTime.wMonth,lpSystemTime.wDay,
       lpSystemTime.wHour,lpSystemTime.wMinute,lpSystemTime.wSecond,lpSystemTime.wMilliseconds,
       iCueNumber,szMsg);
  fclose(fp);
}
else
{
  if (fileFind.nFileSizeLow > 61440)  // if event file size > 60K, delete, create new
  {
   if (DeleteFile(szCurPath))
   {
    if ((fp = fopen(szCurPath,"w")) == NULL)
    {
     return -2;
    }
    fprintf(fp,"%04d-%02d-%02d %02d:%02d:%02d:%03d  Event:%06d  %s\n",
         lpSystemTime.wYear,lpSystemTime.wMonth,lpSystemTime.wDay,
         lpSystemTime.wHour,lpSystemTime.wMinute,lpSystemTime.wSecond,lpSystemTime.wMilliseconds,
         iCueNumber,szMsg);
    fclose(fp);
   }
  }
  else
  {
   if ((fp = fopen(szCurPath,"a+")) == NULL)
   {
    return -3;
   }
   else
   {
    fprintf(fp,"%04d-%02d-%02d %02d:%02d:%02d:%03d  Event:%06d  %s\n",
         lpSystemTime.wYear,lpSystemTime.wMonth,lpSystemTime.wDay,
         lpSystemTime.wHour,lpSystemTime.wMinute,lpSystemTime.wSecond,lpSystemTime.wMilliseconds,
         iCueNumber,szMsg);
    fclose(fp);
   }
  }
}

return VALUE_ZERO;
}

/************************************************************************
Function int WriteToLog:
    write text message to file
Input:
TCHAR *szMsg 文本字符串
OutPut:

return:
use default iCueNumber;
    If no error occurs, returns zero,other returns no zero;
Update:
    Version       Date           Author        Description
    1.0           2008-03-19     Shi Mingjie   Create
************************************************************************/
int WriteToLog(TCHAR *szMsg) // 写日志信息,错误号默认-999
{
const int ERR_DEFAULT = -999;  // 默认的错误消息值
int iReturn;

iReturn = WriteToLog(ERR_DEFAULT,szMsg);

return iReturn;
}

/************************************************************************
Function int WriteBinaryFile:
    write binary data to file
Input:
BYTE* pbtBuffer 数据 不允许为NULL
DWORD dwFileSize 数据大小 合法值大于VALUE_ZERO,小于等于LIMIT_SENDBUFFERSIZE
char *pchFileName 文件名 不允许为NULL
OutPut:

return:
    If no error occurs, returns zero,other returns no zero;
Update:
    Version       Date           Author        Description
    1.0           2008-03-19     Shi Mingjie   Create
************************************************************************/
int WriteBinaryFile(BYTE* pbtBuffer,DWORD dwFileSize,char *pchFileName)
{
FILE* fileWrite;

if ((NULL == pbtBuffer) || (NULL == pchFileName))
{
  return -1;
}

if ((dwFileSize <= VALUE_ZERO) || (dwFileSize > LIMIT_SENDBUFFERSIZE))
{
  return -2;
}

fileWrite = fopen(pchFileName,"wb");
if (fileWrite == NULL)
{
  return -3;
}

if (fwrite(pbtBuffer,1,dwFileSize,fileWrite) != dwFileSize)
{
  fclose(fileWrite);
  return -4;
}

fclose(fileWrite);

return VALUE_ZERO;
}

/************************************************************************
Function int GDW_VM2003_Connect:
    Start InspectThread && Server Thread
Input:
DWORD hWnd 窗口句柄,不能为VALUE_ZERO
DWORD dwMsgDataReady 数据准备好消息,必须大于0x400,默认0x401
DWORD dwMsgConnectSuccess 网络连接成功,必须大于0x401,默认0x402
DWORD dwMsgDisconnect 网络连接断开,必须大于0x402,默认0x403
OutPut:

return:
    If no error occurs, returns zero,other returns no zero;
Update:
    Version       Date           Author        Description
    1.0           2008-03-19     Shi Mingjie   Create
************************************************************************/
extern "C" int PASCAL EXPORT GDW_VM2003_Connect(DWORD hWnd,
DWORD dwMsgDataReady,
DWORD dwMsgConnectSuccess,
DWORD dwMsgDisconnect)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

const DWORD dwMsgMin = 0x400; // 可用消息值临界值(自定义消息必须比该值大)

int    i = 0;
int    iLastSperate = 0;
TCHAR  chCurPath[MAX_PATH];
HANDLE hWndFile;
WIN32_FIND_DATA fileFind;
int    iIsDebugToLog;
TCHAR  chIpBuffer[128];
int    iServerPort;
DWORD  dwReadLength;
int    iRetval = 0;
WORD     wVersion;
WSADATA  wsaData;

if (VALUE_ZERO == hWnd) // 为无效句柄则立即返回
{
  return 2;
}

if ((dwMsgDataReady <= dwMsgMin) ||
  (dwMsgConnectSuccess <= dwMsgMin + 1) ||
  (dwMsgDisconnect <= dwMsgMin + 2) ||
  (dwMsgDataReady == dwMsgConnectSuccess) ||
  (dwMsgDataReady == dwMsgDisconnect) ||
  (dwMsgConnectSuccess == dwMsgDisconnect))
{
  m_udtTcpClient.dwMsgDataReady = dwMsgMin + 1;
  m_udtTcpClient.dwMsgConnectSuccess = dwMsgMin + 2;
  m_udtTcpClient.dwMsgDisconnect = dwMsgMin + 3;
}
else
{
  m_udtTcpClient.dwMsgDataReady = dwMsgDataReady;
  m_udtTcpClient.dwMsgConnectSuccess = dwMsgConnectSuccess;
  m_udtTcpClient.dwMsgDisconnect = dwMsgDisconnect;
}

m_udtTcpClient.hWndProcess = (HWND)hWnd; // 保存消息处理句柄

// 读取配置参数:服务器Ip、端口、是否调试
GetModuleFileName(GetModuleHandle(NULL),chCurPath,MAX_PATH-20);

for (i=0; i {
  if (chCurPath[i] == '\\')
  {
   iLastSperate = i;
  }
  else if(chCurPath[i] == '\0')
  {
   break;
  }
}

if ((iLastSperate > 0) && (i < MAX_PATH-20))
{
  chCurPath[iLastSperate] = '\0';
  strcat(chCurPath,"\\vm2003_client.ini");

  hWndFile = FindFirstFile(chCurPath,&fileFind);
  FindClose(hWndFile);

  if (INVALID_HANDLE_VALUE != hWndFile)
  {
   dwReadLength = GetPrivateProfileString("Client","serverIp","0.0.0.0",chIpBuffer,128,chCurPath);
   if ((dwReadLength >= 7) && (dwReadLength <= 15))
   {
    m_udtTcpClient.dwServerIp = inet_addr(chIpBuffer);
   }
   else
   {
    return 11;
   }

   iServerPort = GetPrivateProfileInt("Client","serverPort",5001,chCurPath);
   if ((iServerPort > 0) && (iServerPort <= 65536))
   {
    m_udtTcpClient.wServerPort = iServerPort;
   }
   else
   {
    return 12;
   }

   iIsDebugToLog = GetPrivateProfileInt("Client","DebugToLog",0,chCurPath);
   if (iIsDebugToLog != 0)
   {
    m_udtTcpClient.bIsDebug = TRUE;
   }
  }
  else
  {
   return -1;
  }
}
else
{
  return -2;
}

// 初始化结构体UDT_TCPCommunicationClient参数
m_udtTcpClient.bConnectActive = FALSE; // 网络是否处于活动状态
m_udtTcpClient.bThreadClientAlive = FALSE; // 线程是否存活
m_udtTcpClient.bDataIsReady = FALSE; // 数据是否准备好
m_udtTcpClient.bIsGetingData = FALSE; // 是否正在取数据
m_udtTcpClient.bIsAdjustTime = FALSE; // 是否校时
m_udtTcpClient.dwReceiveTime = 0; // 收到的服务器回复时间 unix时间格式
m_udtTcpClient.dwHeartBeatTime = 0; // 心跳时间点
m_udtTcpClient.dwHeartBeatCount = 0; // 心跳次数
m_udtTcpClient.sckClient  = NULL; // 客户端线程通讯使用的Socket句柄
m_udtTcpClient.threadClient = NULL; // 客户端线程句柄

m_udtTcpClient.pbtImageNearBuf = NULL; // 特写图片缓存区指针指向NULL
m_udtTcpClient.pbtImageFullBuf = NULL; // 全景图片缓存区指针指向NULL

// 心跳包格式: T L
memcpy(&m_udtTcpClient.pbtSendBufHeartBeat[VALUE_ZERO],&TYPE_HEARTBEAT,PACKET_TYPE_LENGTH);
memcpy(&m_udtTcpClient.pbtSendBufHeartBeat[PACKET_TYPE_LENGTH],&PACKET_HEADER_LENGTH,PACKET_LENGTH_LENGTH);

// 校时包格式: T L V,初始化时复制T L
memcpy(&m_udtTcpClient.pbtSendBufTime[VALUE_ZERO],&TYPE_TIME,PACKET_TYPE_LENGTH);
memcpy(&m_udtTcpClient.pbtSendBufTime[PACKET_TYPE_LENGTH],&PACKET_TIME_LENGTH,PACKET_LENGTH_LENGTH);

InitializeCriticalSection(&m_udtTcpClient.ctsClient); //临界区初始化
m_udtTcpClient.evtInspectEnd.ResetEvent();
m_udtTcpClient.evtClientEnd.ResetEvent(); // Sets the state of the event to nonsignaled

wVersion = MAKEWORD(1,1);

iRetval  = WSAStartup(wVersion,&wsaData);
if (0 != iRetval)
{
  if (m_udtTcpClient.bIsDebug)
  {
   WriteToLog(iRetval,"GDW_VM2003_Connect:没有发现可用的socket通讯库!退出!");
  }
  return -3;
}

if ((LOBYTE(wsaData.wVersion) != 1) || (HIBYTE(wsaData.wVersion) != 1))
{
  if (m_udtTcpClient.bIsDebug)
  {
   WriteToLog("GDW_VM2003_Connect:不是正确的socket通讯库版本!退出!");
  }
  iRetval = WSACleanup();
  if (SOCKET_ERROR == iRetval)
  {
   if (m_udtTcpClient.bIsDebug)
   {
    WriteToLog(iRetval,"GDW_VM2003_Connect:WSACleanup失败!");
   }
  }
  return -4;
}

m_udtTcpClient.sckClient = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == m_udtTcpClient.sckClient)
{
  if (m_udtTcpClient.bIsDebug)
  {
   WriteToLog("GDW_VM2003_Connect:socket 函数返回失败!退出!");
  }
  iRetval = WSACleanup();
  if (SOCKET_ERROR == iRetval)
  {
   if (m_udtTcpClient.bIsDebug)
   {
    WriteToLog(iRetval,"GDW_VM2003_Connect:WSACleanup失败!");
   }
  }
  return -5;
}

if (m_udtTcpClient.bIsDebug)
{
  WriteToLog(0,"[启动]------------------信息分割线------------------");
}

// 建立监测线程
m_udtTcpClient.threadInspect = AfxBeginThread(TcpInspectThread, &m_udtTcpClient, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
m_udtTcpClient.threadInspect->m_bAutoDelete = FALSE;
m_udtTcpClient.threadInspect->ResumeThread();

// 建立通讯服务线程
m_udtTcpClient.threadClient = AfxBeginThread(TcpServerThread, &m_udtTcpClient, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
m_udtTcpClient.threadClient->m_bAutoDelete = FALSE;
m_udtTcpClient.threadClient->ResumeThread();

m_bInitSuccess = TRUE; // 初始化已经成功

return VALUE_ZERO;
}

/************************************************************************
Function int GDW_VM2003_GetVehicleInfo:
    Get Vehicle Info
Input:

OutPut:
char* pchPlate 车牌号码 申请至少20字节空间,不允许NULL
char* pchTime 通行时间 申请至少24字节空间,不允许NULL
BYTE* pbtImageBin 车牌二值化图,不允许NULL
BYTE* pbtImagePlate 车牌彩色图,不允许NULL
DWORD* dwImagePlateSize 车牌彩色图大小
BYTE* pbtImageNear 特写车辆图
DWORD* dwImageNearSize 特写车辆图大小
BYTE* pbtImageFull 全景车辆图
DWORD* dwImageFullSize 全景车辆图大小
char* pchDeviceId 申请至少20字节空间,不允许NULL
int* iRoadWay 车道号
int* iSpeed 车速
int* iSpeedLimit 限速
DWORD* dwDeviceState 设备状态
return:
GDW_VM2003_Connect must call success first;
    If no error occurs, returns zero,other returns no zero;
Update:
    Version       Date           Author        Description
    1.0           2008-03-20     Shi Mingjie   Create
************************************************************************/
extern "C" int PASCAL EXPORT GDW_VM2003_GetVehicleInfo(char* pchPlate,
char* pchTime,
BYTE* pbtImageBin,
BYTE* pbtImagePlate,
DWORD* dwImagePlateSize,
BYTE* pbtImageNear,
DWORD* dwImageNearSize,
BYTE* pbtImageFull,
DWORD* dwImageFullSize,
char* pchDeviceId,
int* iRoadWay,
int* iSpeed,
int* iSpeedLimit,
DWORD* dwDeviceState)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

if (!m_bInitSuccess)
{
  return -1;
}

if (!m_udtTcpClient.bDataIsReady)
{
  return 10;
}

// 参数有空指针直接返回
if ((NULL == pchDeviceId) ||
  (NULL == pchPlate) ||
  (NULL == pchTime) ||
  (NULL == pbtImageNear) ||
  (NULL == pbtImageFull))
{
  return 3;
}

// 设置数据正在读取标记,线程写入等待
EnterCriticalSection(&m_udtTcpClient.ctsClient);
m_udtTcpClient.bIsGetingData = TRUE;
LeaveCriticalSection(&m_udtTcpClient.ctsClient);

strcpy(pchPlate,m_udtTcpClient.udtPassInfo.pchPlate);
strcpy(pchTime,m_udtTcpClient.udtPassInfo.pchPassTime);
strcpy(pchDeviceId,m_udtTcpClient.udtPassInfo.pchDeviceId);

*iRoadWay = m_udtTcpClient.udtPassInfo.iRoadWay;
*iSpeed = m_udtTcpClient.udtPassInfo.iSpeed ;
*iSpeedLimit = m_udtTcpClient.udtPassInfo.iSpeedLimit;
*dwDeviceState = m_udtTcpClient.udtPassInfo.dwDeviceState;
*dwImageNearSize = m_udtTcpClient.udtPassInfo.dwImageNearSize;
*dwImageFullSize = m_udtTcpClient.udtPassInfo.dwImageFullSize;

memcpy(pbtImageNear,m_udtTcpClient.pbtImageNearBuf,m_udtTcpClient.udtPassInfo.dwImageNearSize);
memcpy(pbtImageFull,m_udtTcpClient.pbtImageFullBuf,m_udtTcpClient.udtPassInfo.dwImageFullSize);

// pbtImageBin pbtImagePlate dwImagePlateSize 不赋值

// 设置数据读取完成标记,线程允许写入
EnterCriticalSection(&m_udtTcpClient.ctsClient);
m_udtTcpClient.bIsGetingData = FALSE;
m_udtTcpClient.bDataIsReady = FALSE;
LeaveCriticalSection(&m_udtTcpClient.ctsClient);

return VALUE_ZERO;
}

/************************************************************************
Function int GDW_VM2003_AdjustTime:
    adjust server time
Input:
pchTime must format "yyyyMMddHHmmss"(兼容原定义接口,此参数可不赋值)
OutPut:

return:
GDW_VM2003_Connect must call success first;
    If no error occurs, returns zero,other returns no zero;
Update:
    Version       Date           Author        Description
    1.0           2008-03-19     Shi Mingjie   Create
************************************************************************/
extern "C" int PASCAL EXPORT GDW_VM2003_AdjustTime(char* pchTime)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

time_t unixTime;

if (!m_bInitSuccess)
{
  return 1;
}

if (!m_udtTcpClient.bConnectActive)
{
  return 11;
}

/*********************************************************************
if (NULL == pchTime)
{
  return 2;
}

if (14 != strlen(pchTime))
{
  return 12;
}

struct tm tmTime;
int iASCIIZero = '0';

tmTime.tm_sec  = (pchTime[1]-iASCIIZero) * 10 + (pchTime[0]-iASCIIZero);
tmTime.tm_min  = (pchTime[3]-iASCIIZero) * 10 + (pchTime[2]-iASCIIZero);
tmTime.tm_hour = (pchTime[5]-iASCIIZero) * 10 + (pchTime[4]-iASCIIZero);
tmTime.tm_mday = (pchTime[7]-iASCIIZero) * 10 + (pchTime[6]-iASCIIZero);
tmTime.tm_mon  = (pchTime[9]-iASCIIZero) * 10 + (pchTime[8]-iASCIIZero);
tmTime.tm_year = (pchTime[13]-iASCIIZero) * 1000 + (pchTime[12]-iASCIIZero) * 100 + (pchTime[11]-iASCIIZero) * 10 + (pchTime[10]-iASCIIZero);

if ((tmTime.tm_sec < 0) || (tmTime.tm_sec > 59))
{
  return 8;
}
if ((tmTime.tm_min < 0) || (tmTime.tm_min > 59))
{
  return 7;
}
if ((tmTime.tm_hour < 0) || (tmTime.tm_hour > 23))
{
  return 6;
}
if ((tmTime.tm_mday < 1) || (tmTime.tm_mday > 31))
{
  return 5;
}
if ((tmTime.tm_mon < 1) || (tmTime.tm_mon > 12))
{
  return 4;
}
if ((tmTime.tm_year < 2000) || (tmTime.tm_year > 2099))
{
  return 3;
}

unixTime = mktime(&tmTime);
*********************************************************************/

// 校时没必要那么复杂,省略上一段内容,采用直接获取系统时间
time(&unixTime);

// 写入时间
EnterCriticalSection(&m_udtTcpClient.ctsClient);
memcpy(&m_udtTcpClient.pbtSendBufTime[PACKET_HEADER_LENGTH],&unixTime,sizeof(unixTime));
m_udtTcpClient.bIsAdjustTime = TRUE;
if (m_udtTcpClient.bIsDebug)
{
  WriteToLog(unixTime,"GDW_VM2003_AdjustTime函数:已设置校时。");
}
LeaveCriticalSection(&m_udtTcpClient.ctsClient);

return VALUE_ZERO;
}

/************************************************************************
Function int GDW_VM2003_AdjustTime:
    adjust server time
Input:
pchTime must format "yyyyMMddHHmmss"(兼容原定义接口,此参数可不赋值)
OutPut:

return:
GDW_VM2003_Connect must call success first;
    If no error occurs, returns zero,other returns no zero;
Update:
    Version       Date           Author        Description
    1.0           2008-03-19     Shi Mingjie   Create
************************************************************************/
extern "C" int PASCAL EXPORT GDW_AdjustTime(char* pchTime)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

time_t unixTime;

if (!m_bInitSuccess)
{
  return 1;
}

if (!m_udtTcpClient.bConnectActive)
{
  return 11;
}

// 校时没必要那么复杂,省略上一段内容,采用直接获取系统时间
time(&unixTime);

// 写入时间
EnterCriticalSection(&m_udtTcpClient.ctsClient);
memcpy(&m_udtTcpClient.pbtSendBufTime[PACKET_HEADER_LENGTH],&unixTime,sizeof(unixTime));
m_udtTcpClient.bIsAdjustTime = TRUE;
if (m_udtTcpClient.bIsDebug)
{
  WriteToLog(unixTime,"GDW_VM2003_AdjustTime函数:已设置校时。");
}
LeaveCriticalSection(&m_udtTcpClient.ctsClient);

return VALUE_ZERO;
}


/************************************************************************
Function int GDW_VM2003_Disconnect:
    end listen thread and client thread
Input:

OutPut:

return:
GDW_VM2003_Connect must call success first;
    If no error occurs, returns zero,other returns no zero;
Update:
    Version       Date           Author        Description
    1.0           2008-03-19     Shi Mingjie   Create
************************************************************************/
extern "C" int PASCAL EXPORT GDW_VM2003_Disconnect()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());

DWORD dwExitCode;
DWORD nWaitMilliSecond;
int iReturn = VALUE_ZERO; // 函数返回值
int iRetTmp;      

if (!m_bInitSuccess)
{
  return -1;
}

m_udtTcpClient.evtInspectEnd.SetEvent(); // 通知监测线程终止
m_udtTcpClient.evtClientEnd.SetEvent(); // 通知客户线程终止
  
if (m_udtTcpClient.bThreadClientAlive)
{
  shutdown(m_udtTcpClient.sckClient,SD_BOTH);
  Sleep(DELAY_SHUTDOWNSOCKET);
  closesocket(m_udtTcpClient.sckClient);
  m_udtTcpClient.sckClient = NULL;
}

Sleep(DELAY_SHUTDOWNSOCKET);

nWaitMilliSecond = 0;

if (m_udtTcpClient.threadClient != NULL)
{
  for ( ;; )
  {
   iRetTmp = ::GetExitCodeThread(m_udtTcpClient.threadClient->m_hThread, &dwExitCode);
   if (iRetTmp != 0)
   {
    if (dwExitCode != STILL_ACTIVE)
    {
     break;
    }
    else
    {
     Sleep(DELAY_WAITQUIT);
     nWaitMilliSecond += 1;
     if ((nWaitMilliSecond * DELAY_WAITQUIT) > LIMIT_WAITQUIT)
     {
      iRetTmp = TerminateThread(m_udtTcpClient.threadClient->m_hThread,1);
      if (iRetTmp != 0) // 终止线程成功
      {
       break;
      }
      else // 终止线程失败
      {
       iReturn = -10;
       break;
      }
     }
    }
   }
   else
   {
    break;
   }
  }
}
m_udtTcpClient.threadClient = NULL;

if (NULL != m_udtTcpClient.pbtImageNearBuf)
{
  delete[] m_udtTcpClient.pbtImageNearBuf;
  m_udtTcpClient.pbtImageNearBuf = NULL;
}
if (NULL != m_udtTcpClient.pbtImageFullBuf)
{
  delete[] m_udtTcpClient.pbtImageFullBuf;
  m_udtTcpClient.pbtImageFullBuf = NULL;
}

iRetTmp = ::GetExitCodeThread(m_udtTcpClient.threadInspect->m_hThread, &dwExitCode);
if (iRetTmp != 0)
{
  if (dwExitCode != STILL_ACTIVE)
  {
   // 已终止
  }
  else
  {
   iRetTmp = TerminateThread(m_udtTcpClient.threadInspect->m_hThread,1);
   if (iRetTmp != 0) // 终止线程成功
   {
    
   }
   else // 终止线程失败
   {
    iReturn = -11;
   }
  }
}

WSACleanup();

m_bInitSuccess = FALSE;

if (m_udtTcpClient.bIsDebug)
{
  WriteToLog(0,"[终止]------------------信息分割线------------------");
}

return iReturn;
}

/************************************************************************
Function int TcpReceive:
    receive data from socket
Input:
SOCKET sckClient 接收数据的socket句柄
int iOffset 接收的偏移位置
int iReceiveSize 接收的大小
int iOverTime 接收的超时限制
OutPut:
BYTE *pchBuffer 接收缓存区
return:
    If no error occurs, returns receive data size,other returns SOCKET_ERROR or zero;
Update:
    Version       Date           Author        Description
    1.0           2008-03-19     Shi Mingjie   Create
************************************************************************/
int TcpReceive(SOCKET sckClient,
BYTE *pchBuffer,
int iOffset,
int iReceiveSize,
int iOverTime)
{
int iRev;
int iHaveRev;
int iReadTimes;
int iReadTimesLimit;

iReadTimesLimit = iOverTime / DELAY_WAITSUCCESS;
iReadTimes = 0;
iHaveRev = 0;
Sleep(DELAY_WAITSUCCESS);
iRev = recv(sckClient,(char *)&pchBuffer[iOffset+iHaveRev],iReceiveSize,0);
if (SOCKET_ERROR == iRev)
{
  return SOCKET_ERROR;
}
else
{
  iHaveRev += iRev;
}
while ((iHaveRev < iReceiveSize) && (iReadTimes++ < iReadTimesLimit))
{
  Sleep(DELAY_WAITSUCCESS);
  iRev = recv(sckClient,(char *)&pchBuffer[iOffset+iHaveRev],iReceiveSize-iHaveRev,0);
  if (SOCKET_ERROR == iRev)
  {
   return SOCKET_ERROR;
  }
  else
  {
   iHaveRev += iRev;
  }
}

if (iHaveRev == iReceiveSize)
{
  return iHaveRev;
}
else
{
  return VALUE_ZERO;
}
}

/************************************************************************
Function int TcpInspectThread:
    inspect thread (通过此线程与服务器建立socket连接并监测连接状态)
Input:
UDT_TCPCommunicationClient m_udtTcpClient
OutPut:
UDT_TCPCommunicationClient m_udtTcpClient
return:
    If no error occurs, returns zero,other returns no zero;
Update:
    Version       Date           Author        Description
    1.0           2008-03-20     Shi Mingjie   Create
************************************************************************/
UINT TcpInspectThread(LPVOID pParam)
{
struct UDT_TCPCommunicationClient *pudtTcpConnect = (struct UDT_TCPCommunicationClient *)pParam;
struct sockaddr_in serverAddr;
DWORD  dwTimeCountInterval; // 时间差值
int iRetval;
//DWORD dwServerIp;
//dwServerIp = inet_addr("192.168.58.10");
//memcpy(&serverAddr.sin_addr, &dwServerIp, sizeof(dwServerIp));
//serverAddr.sin_port = htons(6999);

memcpy(&serverAddr.sin_addr, &pudtTcpConnect->dwServerIp, sizeof(pudtTcpConnect->dwServerIp));
serverAddr.sin_port = htons(pudtTcpConnect->wServerPort);
serverAddr.sin_family = AF_INET;

if (pudtTcpConnect->bIsDebug)
{
  WriteToLog(0,"TcpInspectThread线程:启动。");
}

for (; ;)
{
  if (WAIT_OBJECT_0 == ::WaitForSingleObject(pudtTcpConnect->evtInspectEnd.m_hObject, 0))
  {
   if (pudtTcpConnect->bIsDebug)
   {
    WriteToLog(0,"TcpInspectThread线程:接收到信号量终止指令。");
   }
   break;
  }

  if (!pudtTcpConnect->bConnectActive) // 网络未连接
  {
   if (NULL != pudtTcpConnect->sckClient)
   {
    shutdown(pudtTcpConnect->sckClient,SD_BOTH);
    Sleep(DELAY_WAITSUCCESS);
    closesocket(pudtTcpConnect->sckClient);
    pudtTcpConnect->sckClient = NULL;
   }
   pudtTcpConnect->sckClient = socket(AF_INET, SOCK_STREAM, 0);
   if (INVALID_SOCKET == pudtTcpConnect->sckClient)
   {
    if (pudtTcpConnect->bIsDebug)
    {
     WriteToLog("TcpInspectThread线程:socket 函数返回失败。");
    }
   }

   iRetval = connect(pudtTcpConnect->sckClient,(struct sockaddr *)&serverAddr,sizeof(serverAddr));
   if (SOCKET_ERROR == iRetval)
   {
    if (pudtTcpConnect->bIsDebug)
    {
     WriteToLog(iRetval,"TcpInspectThread线程:connect 连接失败!");
    }
   }
   else if(0 == iRetval) // 建立连接成功
   {
    EnterCriticalSection(&pudtTcpConnect->ctsClient);
    pudtTcpConnect->bConnectActive = TRUE; // 连接成功标志置为TRUE
    LeaveCriticalSection(&pudtTcpConnect->ctsClient);

    PostMessage(pudtTcpConnect->hWndProcess, pudtTcpConnect->dwMsgConnectSuccess,0,0);

    pudtTcpConnect->dwHeartBeatTime = GetTickCount(); // 默认上次心跳时间点为启动线程时间

    if (pudtTcpConnect->bIsDebug)
    {
     WriteToLog(0,"TcpInspectThread线程:connect 连接成功。");
    }
   }
   else
   {
    WriteToLog(iRetval,"TcpInspectThread线程:connect 返回异常值!");
   }
  }
  else
  {
   dwTimeCountInterval = GetTickCount() - pudtTcpConnect->dwHeartBeatTime;
   if ((dwTimeCountInterval > LIMIT_HEARTBEAT) && (GetTickCount() > pudtTcpConnect->dwHeartBeatTime))
   {
    EnterCriticalSection(&pudtTcpConnect->ctsClient);
    pudtTcpConnect->bConnectActive = FALSE; // 连接成功标志置为FALSE,通过心跳是否超时检测连接是否失效
    LeaveCriticalSection(&pudtTcpConnect->ctsClient);
    PostMessage(pudtTcpConnect->hWndProcess, pudtTcpConnect->dwMsgDisconnect,0,0);

    if (pudtTcpConnect->bIsDebug)
    {
     WriteToLog(dwTimeCountInterval,"TcpInspectThread线程:检测到心跳超时,重新连接!");
    }
   }
  }

  Sleep(DELAY_INSPECT);
}

return VALUE_ZERO;
}

/************************************************************************
Function int TcpServerThread:
    server thread (通过此线程与服务器端进行通讯)
Input:
UDT_TCPCommunicationClient m_udtTcpClient
OutPut:
UDT_TCPCommunicationClient m_udtTcpClient
return:
    If no error occurs, returns zero,other returns no zero;
Update:
    Version       Date           Author        Description
    1.0           2008-03-20     Shi Mingjie   Create
************************************************************************/
UINT TcpServerThread(LPVOID pParam)
{
struct UDT_TCPCommunicationClient *pudtTcpClient = (struct UDT_TCPCommunicationClient *)pParam;

int iSendRetval;
BYTE   pbtReceiveBuf[LIMIT_SENDBUFFERSIZE];
int    iRealReceive = 0;
int    iReceiveRetval = 0;
short  siType = 0; // 接收到的包类型
int    iLength = 0; // 接收到的包长度
int    iToalLength = 0; // 接收到的包总长度
int    iImageNearSize = 0; // 接收到的近景图片数据尺寸
int    iImageFullSize = 0; // 接收到的全景图片数据尺寸
DWORD  dwTimeCountInterval; // 时间差值
int    iWaitTimes = 0;
const long TIMEOUT_RECEIVECHECK = 200000; // 单位为microseconds 微妙
struct timeval tvReceive={0,TIMEOUT_RECEIVECHECK};  
fd_set fdReceive;  
int iSelectRet; // Select函数的返回值


pudtTcpClient->bThreadClientAlive = TRUE;
if (pudtTcpClient->bIsDebug)
{
  WriteToLog(0,"TcpServerThread线程:启动。");
}

for (; ;)
{
  if (WAIT_OBJECT_0 == ::WaitForSingleObject(pudtTcpClient->evtClientEnd.m_hObject, 0))
  {
   if (pudtTcpClient->bIsDebug)
   {
    WriteToLog(0,"TcpServerThread线程:接收到信号量终止指令。");
   }
   break;
  }
  
  // 网络已连接:接包
  if (pudtTcpClient->bConnectActive)
  {
   FD_ZERO(&fdReceive);    
   FD_SET(pudtTcpClient->sckClient,&fdReceive);
   iSelectRet = select(0,&fdReceive,NULL,NULL,&tvReceive);    
  
   switch (iSelectRet)    
   {  
   case SOCKET_ERROR: // SOCKET_ERROR if an error occurred.  
    if (pudtTcpClient->bIsDebug)
    {
     WriteToLog(iSelectRet,"TcpServerThread线程:select 返回ZERO!");
    }
    break;
   case VALUE_ZERO: // zero if the time limit expired                                          
    break;
   default: // the total number of socket handles that are ready and contained in the fd_set structures                
    if (FD_ISSET(pudtTcpClient->sckClient,&fdReceive))
    {  
     Sleep(DELAY_WAITSUCCESS);
     iRealReceive = 0;
     iReceiveRetval = recv(pudtTcpClient->sckClient,(char *)&pbtReceiveBuf[iRealReceive],PACKET_HEADER_LENGTH,0);
     if (SOCKET_ERROR == iReceiveRetval)
     {
      // pudtTcpClient->evtClientEnd.SetEvent();
      WriteToLog(iReceiveRetval,"TcpServerThread线程:recv 返回SOCKET_ERROR,继续!");
      pudtTcpClient->bConnectActive = FALSE;
      PostMessage(pudtTcpClient->hWndProcess, pudtTcpClient->dwMsgDisconnect,0,0);
      break;
     }
     else if (VALUE_ZERO == iReceiveRetval) // If the connection has been gracefully closed, the return value is zero.
     {
      // pudtTcpClient->evtClientEnd.SetEvent();
      WriteToLog(iReceiveRetval,"TcpServerThread线程:recv 返回VALUE_ZERO,客户端连接完美关闭,继续!");
      pudtTcpClient->bConnectActive = FALSE;
      PostMessage(pudtTcpClient->hWndProcess, pudtTcpClient->dwMsgDisconnect,0,0);
      break;
     }
     else // If no error occurs, recv returns the number of bytes received.
     {
      siType = 0;
      iLength = 0;

      if (PACKET_HEADER_LENGTH != iReceiveRetval)
      {
       WriteToLog(iReceiveRetval,"TcpServerThread线程:1次未接收满 PACKET_HEADER_LENGTH字节。");
      }
      else
      {      
       memcpy(&siType,&pbtReceiveBuf[VALUE_ZERO],PACKET_TYPE_LENGTH); //包类型 2BYTE
       memcpy(&iLength,&pbtReceiveBuf[PACKET_TYPE_LENGTH],PACKET_LENGTH_LENGTH); //包长度 4BYTE
       iRealReceive += iReceiveRetval;

       switch (siType)
       {
       case TYPE_HEARTBEAT: // 心跳包
        if (pudtTcpClient->bIsDebug)
        {
         WriteToLog(pudtTcpClient->dwHeartBeatTime,"TcpServerThread线程:接收心跳包正常。");
        }
        break;
       case TYPE_TIME: // 时间包
        iReceiveRetval = recv(pudtTcpClient->sckClient,(char *)&pbtReceiveBuf[iRealReceive],iLength-PACKET_HEADER_LENGTH,0);
        if (SOCKET_ERROR == iReceiveRetval)
        {
         if (pudtTcpClient->bIsDebug)
         {
          WriteToLog("TcpServerThread线程:接收时间数据发生错误!");
         }
         break;
        }
        else if (VALUE_ZERO == iReceiveRetval)
        {
         break;
        }
        else
        {
         memcpy(&pudtTcpClient->dwReceiveTime,&pbtReceiveBuf[iRealReceive],sizeof(pudtTcpClient->dwReceiveTime));

         if (pudtTcpClient->bIsDebug)
         {
          WriteToLog(pudtTcpClient->dwReceiveTime,"TcpServerThread线程:校时成功,接收到服务器时间。");
         }
        }
        break;
       case TYPE_REALVEHICLE: // 实时车辆信息包
        iToalLength = iLength;
      
        // 接收子包1 :通行信息包 TYPE_PASSINFO
        iReceiveRetval = recv(pudtTcpClient->sckClient,(char *)&pbtReceiveBuf[iRealReceive],PACKET_HEADER_LENGTH,0);
        if (SOCKET_ERROR == iReceiveRetval)
        {
         break;
        }
        else if (VALUE_ZERO == iReceiveRetval)
        {
         break;
        }
        else
        {
         memcpy(&siType,&pbtReceiveBuf[iRealReceive],PACKET_TYPE_LENGTH); //包类型 2BYTE
         memcpy(&iLength,&pbtReceiveBuf[iRealReceive + PACKET_TYPE_LENGTH],PACKET_LENGTH_LENGTH); //包长度 4BYTE    
         iRealReceive += iReceiveRetval;

         if (TYPE_PASSINFO == siType) // 通行信息包
         {
          iReceiveRetval = TcpReceive(pudtTcpClient->sckClient,pbtReceiveBuf,iRealReceive,iLength-PACKET_HEADER_LENGTH,LIMIT_WAITRECEIVE);
          if (SOCKET_ERROR == iReceiveRetval)
          {
           break;
          }
          else if (VALUE_ZERO == iReceiveRetval)
          {
           break;
          }
          else
          {
           iWaitTimes = 0;
           while ((pudtTcpClient->bIsGetingData) && (iWaitTimes < LIMIT_WAITQUIT/DELAY_WAITSUCCESS))
           {
            Sleep(DELAY_WAITSUCCESS);
            iWaitTimes++;
           }

           memcpy(&pudtTcpClient->udtPassInfo,&pbtReceiveBuf[iRealReceive],sizeof(pudtTcpClient->udtPassInfo));
           iRealReceive += iReceiveRetval;
          }
         }
        }

        // 接收子包2 :特写图片数据包 TYPE_IMAGENEAR
        iReceiveRetval = recv(pudtTcpClient->sckClient,(char *)&pbtReceiveBuf[iRealReceive],PACKET_HEADER_LENGTH,0);
        if (SOCKET_ERROR == iReceiveRetval)
        {
         break;
        }
        else if (VALUE_ZERO == iReceiveRetval)
        {
         break;
        }
        else
        {
         memcpy(&siType,&pbtReceiveBuf[iRealReceive],PACKET_TYPE_LENGTH); //包类型 2BYTE
         memcpy(&iLength,&pbtReceiveBuf[iRealReceive + PACKET_TYPE_LENGTH],PACKET_LENGTH_LENGTH); //包长度 4BYTE    
         iRealReceive += iReceiveRetval;
      
         if (TYPE_IMAGENEAR == siType) // 特写图片数据包
         {
          iReceiveRetval = TcpReceive(pudtTcpClient->sckClient,pbtReceiveBuf,iRealReceive,iLength-PACKET_HEADER_LENGTH,LIMIT_WAITRECEIVE);
          if (SOCKET_ERROR == iReceiveRetval)
          {
           break;
          }
          else if (VALUE_ZERO == iReceiveRetval)
          {
           break;
          }
          else
          {
           if (NULL != pudtTcpClient->pbtImageNearBuf)
           {
            delete[] pudtTcpClient->pbtImageNearBuf;
            pudtTcpClient->pbtImageNearBuf = NULL;
           }
           iImageNearSize = iLength - PACKET_HEADER_LENGTH;
           if ((iImageNearSize < LIMIT_MINIMAGESIZE) || (iImageNearSize > LIMIT_MAXIMAGESIZE))
           {
            // 近景图片大小不正确,退出
            if (pudtTcpClient->bIsDebug)
            {
             WriteToLog(iImageNearSize,"TcpServerThread线程:近景图片长度不合法。");
            }
            break;
           }
           pudtTcpClient->pbtImageNearBuf = new BYTE[iImageNearSize];
           memcpy(pudtTcpClient->pbtImageNearBuf,&pbtReceiveBuf[iRealReceive],iImageNearSize);
           iRealReceive += iReceiveRetval;
          }
         }
        }

        // 接收子包3 :全景图片数据包 TYPE_IMAGEFULL
        iReceiveRetval = recv(pudtTcpClient->sckClient,(char *)&pbtReceiveBuf[iRealReceive],PACKET_HEADER_LENGTH,0);
        if (SOCKET_ERROR == iReceiveRetval)
        {
         break;
        }
        else if (VALUE_ZERO == iReceiveRetval)
        {
         break;
        }
        else
        {
         memcpy(&siType,&pbtReceiveBuf[iRealReceive],PACKET_TYPE_LENGTH); //包类型 2BYTE
         memcpy(&iLength,&pbtReceiveBuf[iRealReceive + PACKET_TYPE_LENGTH],PACKET_LENGTH_LENGTH); //包长度 4BYTE    
         iRealReceive += iReceiveRetval;

         if (TYPE_IMAGEFULL == siType) // 全景图片数据包
         {
          iReceiveRetval = TcpReceive(pudtTcpClient->sckClient,pbtReceiveBuf,iRealReceive,iLength-PACKET_HEADER_LENGTH,LIMIT_WAITRECEIVE);
          if (SOCKET_ERROR == iReceiveRetval)
          {
           break;
          }
          else if (VALUE_ZERO == iReceiveRetval)
          {
           break;
          }
          else
          {
           if (NULL != pudtTcpClient->pbtImageFullBuf)
           {
            delete[] pudtTcpClient->pbtImageFullBuf;
            pudtTcpClient->pbtImageFullBuf = NULL;
           }
           iImageFullSize = iLength - PACKET_HEADER_LENGTH;
           if ((iImageFullSize < LIMIT_MINIMAGESIZE) || (iImageFullSize > LIMIT_MAXIMAGESIZE))
           {
            // 全景图片大小不正确,退出
            if (pudtTcpClient->bIsDebug)
            {
             WriteToLog(iImageFullSize,"TcpServerThread线程:全景图片长度不合法。");
            }
            break;
           }
           pudtTcpClient->pbtImageFullBuf = new BYTE[iImageFullSize];
           memcpy(pudtTcpClient->pbtImageFullBuf,&pbtReceiveBuf[iRealReceive],iImageFullSize);
           iRealReceive += iReceiveRetval;
          }
         }
        }
        EnterCriticalSection(&pudtTcpClient->ctsClient);
        pudtTcpClient->bDataIsReady = TRUE;
        LeaveCriticalSection(&pudtTcpClient->ctsClient);
        PostMessage(pudtTcpClient->hWndProcess, pudtTcpClient->dwMsgDataReady,0,0);
        break;
       default:
        WriteToLog(siType,"TcpServerThread线程:T-L-V协议T不属于已定义类型!继续!");
        // pudtTcpClient->evtClientEnd.SetEvent();
        pudtTcpClient->bConnectActive = FALSE;
        PostMessage(pudtTcpClient->hWndProcess, pudtTcpClient->dwMsgDisconnect,0,0);
        break;
       }
      } // 接收到PACKET_HEADER_LENGTH字节的字符      
     }
    } // end if (FD_ISSET(pudtTcpClient->sckClient,&fdReceive))
    else
    {
     if (pudtTcpClient->bIsDebug)
     {
      WriteToLog("TcpServerThread线程:FD_ISSET 返回ZERO!");
     }
    }
    break;
   }  
  
   // 网络已连接:检查是否发送心跳包
   if (pudtTcpClient->bConnectActive)
   {
    dwTimeCountInterval = GetTickCount() - pudtTcpClient->dwHeartBeatTime;
    if (dwTimeCountInterval > DELAY_HEARTBEATINTERVAL)
    {
     iSendRetval = send(pudtTcpClient->sckClient,(char *)pudtTcpClient->pbtSendBufHeartBeat,PACKET_HEADER_LENGTH,0);  
     if (SOCKET_ERROR == iSendRetval)
     {
      if (pudtTcpClient->bIsDebug)
      {
       WriteToLog(iSendRetval,"TcpServerThread线程:心跳包发送失败!");
      }
     }
     else
     {
      pudtTcpClient->dwHeartBeatTime = GetTickCount(); // 发送成功即认为成功
      if (pudtTcpClient->bIsDebug)
      {
       WriteToLog(iSendRetval,"TcpServerThread线程:心跳包发送成功。");
      }
     }
    }
   }

   // 网络已连接:检查是否进行校时
   if (pudtTcpClient->bConnectActive)
   {
    if (pudtTcpClient->bIsAdjustTime)
    {
     iSendRetval = send(pudtTcpClient->sckClient,(char *)pudtTcpClient->pbtSendBufTime,PACKET_TIME_LENGTH,0);  
     if (SOCKET_ERROR == iSendRetval)
     {
      if (pudtTcpClient->bIsDebug)
      {
       WriteToLog(iSendRetval,"TcpServerThread线程:校时包发送失败!");
      }
     }
     else
     {
      EnterCriticalSection(&pudtTcpClient->ctsClient);
      pudtTcpClient->bIsAdjustTime = FALSE; // 发送成功即认为成功
      LeaveCriticalSection(&pudtTcpClient->ctsClient);

      if (pudtTcpClient->bIsDebug)
      {
       WriteToLog(iSendRetval,"TcpServerThread线程:校时包发送成功。");
      }
     }
    }
   }
  }

  Sleep(DELAY_WAITSUCCESS);
}

shutdown(pudtTcpClient->sckClient,SD_BOTH);
closesocket(pudtTcpClient->sckClient);

pudtTcpClient->bConnectActive = FALSE;
pudtTcpClient->bThreadClientAlive = FALSE;

return VALUE_ZERO;
}
10/05 18
如我的MySQL进程为:1918

#cat /proc/1918/smaps
[root@mon-bjds-bw-220-169 1918]# cat smaps
002b7000-002c0000 r-xp 00000000 08:02 2875176    /lib/libnss_files-2.5.so
Size:                36 kB
Rss:                 20 kB
Shared_Clean:        20 kB
Shared_Dirty:         0 kB
Private_Clean:        0 kB
Private_Dirty:        0 kB
Swap:        0 kB
002c0000-002c1000 r-xp 00008000 08:02 2875176    /lib/libnss_files-2.5.so
Size:                 4 kB
Rss:                  4 kB
Shared_Clean:         0 kB
Shared_Dirty:         0 kB
Private_Clean:        0 kB
Private_Dirty:        4 kB
Swap:        0 kB
......

有了这些信息,就可以分析程序性能表现了。
10/04 19
参考资料:

1。Linux下的多线程编程
http://linux.chinaunix.net/doc/program/2001-08-11/642.shtml
2。pthread_delay_np(这里头有个关于posix条件变量的例子)
http://bbs.chinaunix.net/archiver/?tid-584593.html
3。pthread_join和段错误(非常感谢这里头的哥们,千万要看哦)
http://www.bczs.net/xml/2005/11/5/4374188.xml
4。posix线程编程指南[学习linux下多线程,不看这个你会后悔的]
http://www.linuxforum.net/forum/showflat.php?Cat=&Board=program&Number=294073&page=0&view=collapsed&sb=5&o=7&fpart=
Tags:
10/02 3
http://code.google.com/p/qgserver/

QGServerLib是一个C++实现的简单易用的Tcp服务器框架库,旨在简化服务器的构建过程。具有如下特点:

1, 以模块化的处理池为基本构建元素,能够方便的实现安全稳定的服务架构。

2,事件触发,多线程事件监听,任务化读写访问,解决单线程监听及数据读写带来的性能瓶颈,连接不受线程数限制。

3,写队列,并行读写逻辑,支持服务器数据推送(Push)。

4,数据传送协议,避免数据传送错误,封装数据流。

5,类远过程调用。

6,提供相配套的ActionScript脚本客户端。能够方便的实现网页实时通讯,解决传统网页通讯的消息轮询问题。
Tags:
10/02 3

http://zhoulifa.bokee.com/5351040.html
http://lse.sourceforge.net/epoll/index.html
http://www.hudong.com/wiki/epoll

Epoll是Linux内核为处理大批量句柄而作了改进的poll。要使用epoll只需要这三个系统调用:epoll_create(2), epoll_ctl(2), epoll_wait(2)。它是在2.5.44内核中被引进的(epoll(4) is a new API introduced in Linux kernel 2.5.44),在2.6内核中得到广泛应用,例如LightHttpd。
Tags:
10/02 3

C libevent 不指定

jason , 22:07 , 我的收藏 » C / C++ , 评论(0) , 引用(0) , 阅读(3136) , Via 本站原创
http://blog.gslin.info/2005/11/network-programming-using-libevent-i.html
http://zh.wikipedia.org/wiki/Libevent
Tags: ,
10/01 29
堆(Heap)栈(Stack)

1、内存分配方面:

    堆:一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式是类似于链表。可能用到的关键字如下:new、malloc、delete、free等等。

    栈:由编译器(Compiler)自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

2、申请方式方面:

    堆:需要程序员自己申请,并指明大小。在c中malloc函数如p1 = (char *)malloc(10);在C++中用new运算符,但是注意p1、p2本身是在栈中的。因为他们还是可以认为是局部变量。

    栈:由系统自动分配。 例如,声明在函数中一个局部变量 int b;系统自动在栈中为b开辟空间。

3、系统响应方面:

    堆:操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样代码中的delete语句才能正确的释放本内存空间。另外由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

    栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。

4、大小限制方面:

    堆:是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

    栈:在Windows下, 栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是固定的(是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。

5、效率方面:

    堆:是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便,另外,在WINDOWS下,最好的方式是用 VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。

    栈:由系统自动分配,速度较快。但程序员是无法控制的。

6、存放内容方面:

    堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。

    栈:在函数调用时第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈,然后是函数中的局部变量。 注意: 静态变量是不入栈的。当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。

7、存取效率方面:

    堆:char *s1 = "Hellow Word";是在编译时就确定的;

    栈:char s1[] = "Hellow Word"; 是在运行时赋值的;用数组比用指针速度要快一些,因为指针在底层汇编中需要用edx寄存器中转一下,而数组在栈上直接读取。
分页: 1/3 第一页 1 2 3 下页 最后页 [ 显示模式: 摘要 | 列表 ]