织梦CMS - 轻松建站从此开始!

罗索

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

jackyhwei 发布于 2010-01-01 12:17 点击:次 
多线程TCP/IP通讯的客户端,心跳检测,意外断网重连,时间校准。写日志函数不考虑线程同步。
TAG:

/* 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)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201001/8206.html]
本文出处:CSDN.NET 作者:YFY
顶一下
(3)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容