您的位置:首页 > 理论基础 > 计算机网络

多线程TCP/IP通讯的客户端

2012-12-30 23:40 489 查看



jackyhwei 发布于 2010-01-01 12:17 点击:842次

多线程TCP/IP通讯的客户端,心跳检测,意外断网重连,时间校准。写日志函数不考虑线程同步。

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)

本站文章除
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: