TLV 协议

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

dev.firnow.com时间:2008-04-14作者:佚名 编辑:本站 点击:2573 [评论]

/* 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;
}

你可能感兴趣的:(多线程,socket,网络协议,pascal,FP)