多线程TCP/IP通讯的客户端
2012-12-30 23:40
489 查看
jackyhwei 发布于 2010-01-01 12:17 点击:842次 |
TAG: 多线程 TCP 心跳 服务器编程 TLV
/* add include files */ #include "winsock2.h" #include "afxmt.h" #include "Mmsystem.h" #include <time.h> #include <sys/types.h> #include <sys/timeb.h> #include <string.h> //////////////////////////////////////////////////////////////////////// // 传输协议根据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<MAX_PATH-20; 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; } (YFY) |
相关文章推荐
- 多线程TCP/IP通讯的客户端
- 多线程TCP/IP通讯的客户端
- TCP/IP 多线程服务端多客户端通信 readLine
- 多线程TCP/IP通讯的服务端
- TCP/IP多线程——聊天室(客户端 )
- 调用TCP/IP通讯客户端的VB6样例
- Linux Socket编程:基于TCP/IP的客户端与服务端通讯实例
- 多线程TCP/IP通讯的服务端
- http,socket,tcp/ip 网络传输与通讯知识总结
- Socket 服务端使用多线程实现多客户端通讯实例
- [置顶] 使用多线程实现多客户端的连接(通过Socket实现TCP编程)
- Android通过Socket(TCP/IP)与PC通讯
- 网络编程_TCP_Socket通信_聊天室_客户端多线程_群聊JAVA191-192
- C++基于TCP/IP简单的客户端、服务器通信程序实例
- VC++ Socket编程 简单的Tcp/ip客户端
- Android通过Socket(TCP/IP)与PC通讯
- 客户端需要建立和管理多个TCP/IP连接
- 一个简单的TCP/IP服务端客户端对话
- 通讯http,TCP/IP与socket之间的区别