多线程TCP/IP通讯的服务端

/* 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 = 100; // 检查网络状态的间隔

const int LIMIT_WAITRECEIVE = 200; // 等待接收最长时间
const int LIMIT_WAITQUIT = 200; // 退出延时限制
const int LIMIT_DATAOVERTIME = 10000; // 数据超时限制(保存在发送缓存中的)
const int LIMIT_HEARTBEAT = 30000; // 心跳间隔超时限制(超出认为服务器异常)
const int LIMIT_MAXLISTENCLIENT = 128; // 最大监听客户数
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 VALUE_ZERO = 0; // 零值
const int VALUE_ALIVE = 1; // 存活

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_TCPCommunicationServer // 通讯控制参数结构体
{
    HWND hWndProcess; // 调用主程序主窗口句柄

 WORD wListenPort; // 监听Socket端口
 BOOL bIsDebug; // 是否调试
 BOOL bIsQuitListen; // 是否退出监听

 SOCKET sckListen; // 监听Socket句柄
 BOOL bListenAlive; // 监听Socket是否处于活动状态(是否在运行)
 CString strListenMsg; // 监听线程的消息保存区
 CWinThread* threadListen; // 监听Socket线程句柄
 CRITICAL_SECTION ctsListen; // 监听线程的临界保护变量
 
 BOOL bClientAlive; // 客户端线程是否处于活动状态(是否在运行)
    BYTE btClientIp[4]; // 客户端Ip地址
 SOCKET sckClient; // 客户端线程通讯使用的Socket句柄
 CWinThread* threadClient; // 客户端线程句柄
 CRITICAL_SECTION ctsClient; // 客户端临界区
 CEvent evtClientEnd;  // 客户端线程信号量(通知对应线程结束)

 BOOL bIsReady; // 数据是否准备好
 BOOL bIsSending; // 是否在发送过程中
 DWORD dwPutTimeCount; // 放入数据的时间点
 DWORD dwSendTimeCount; // 发送数据的时间点
 DWORD dwHeartBeatTimeCount; // 心跳时间点
 DWORD dwPutCount; // 服务器端放入的记录统计
 DWORD dwSendCount; // 服务器端发送的记录统计
 
 struct UDT_PassInfo udtPassInfo; // 车辆信息数据包(不包括图片)
 BYTE pbtSendBufHeartBeat[PACKET_HEADER_LENGTH]; // 心跳包发送缓存区
 BYTE pbtSendBufTime[PACKET_TIME_LENGTH]; // 时间包发送缓存区
 BYTE pbtSendBuf[LIMIT_SENDBUFFERSIZE]; // 通用包发送缓存区
 int iSendTotalLength; // 通用包发送总长度
}UDT_TCPCommunicationServer;

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

UINT TcpClientThread(LPVOID pParam);
UINT TcpListenThread(LPVOID pParam);
int WriteToLog(int iCueNumber,TCHAR *szMsg);
int WriteToLog(TCHAR *szMsg);
int WriteBinaryFile(BYTE* pbtBuffer,DWORD dwFileSize,char *pchFileName);

/*******************************************************
int GDW_VM2003Server_Start(DWORD hWnd);
int GDW_VM2003Server_Send(char* pchDeviceId,
 int iRoadWay,
 char* pchPlate,
 char* pchTime,
 int iSpeed,
 int iSpeedLimit,
 DWORD dwDeviceState,
 int iImageNumber,
 DWORD dwImageNearSize,
 BYTE* pbtImageNear,
 DWORD dwImageFullSize,
 BYTE* pbtImageFull);
int GDW_VM2003Server_End();
*******************************************************/

//
// 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_Server.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_VM2003Server_Start:
    Init && Start listen thread
Input:
 DWORD hWnd 接收消息的窗口句柄,不能为0值
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_VM2003Server_Start(DWORD hWnd)
{
 AFX_MANAGE_STATE(AfxGetStaticModuleState());

 int    i = 0;
 int    iLastSperate = 0;
 int    iIsDebugToLog;
 int    iProtocalVersion;
 TCHAR  chCurPath[MAX_PATH]; 
 HANDLE hWndFile;
 WIN32_FIND_DATA fileFind;
 
 if (VALUE_ZERO == hWnd) // 为无效句柄则立即返回
 {
  return -1;
 }

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

 // 读取配置参数:Tcp监听端口
 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_server.ini");

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

  if (INVALID_HANDLE_VALUE != hWndFile)
  {
   m_udtTcpServer.wListenPort = GetPrivateProfileInt("Server","ListenPort",5001,chCurPath);
   iIsDebugToLog = GetPrivateProfileInt("Server","DebugToLog",0,chCurPath);
   iProtocalVersion = GetPrivateProfileInt("Server","ProtocalVersion",1000,chCurPath);
   if (iIsDebugToLog != 0)
   {
    m_udtTcpServer.bIsDebug = TRUE;
   }
   m_udtTcpServer.udtPassInfo.dwProtocalVersion = (DWORD)iProtocalVersion;
  }
  else
  {
   m_udtTcpServer.wListenPort = 5001;
   m_udtTcpServer.bIsDebug = FALSE;
   m_udtTcpServer.udtPassInfo.dwProtocalVersion = 999;
  }
 }
 else
 {
  m_udtTcpServer.wListenPort = 5001;
  m_udtTcpServer.bIsDebug = FALSE;
  m_udtTcpServer.udtPassInfo.dwProtocalVersion = 999;
 }
 
 // 初始化结构体UDT_TCPCommunicationServer参数
 m_udtTcpServer.bIsQuitListen = FALSE;
 m_udtTcpServer.bListenAlive = FALSE;
 m_udtTcpServer.sckListen = NULL;
 m_udtTcpServer.threadListen = NULL;
 m_udtTcpServer.strListenMsg = "";
 
 m_udtTcpServer.bClientAlive = FALSE;
 for (i=0; i<4; i++)
 {
  m_udtTcpServer.btClientIp[i] = 0;
 }
 m_udtTcpServer.sckClient  = NULL;
 m_udtTcpServer.threadClient = NULL;
 
 m_udtTcpServer.bIsReady = FALSE;
 m_udtTcpServer.bIsSending = FALSE;
 m_udtTcpServer.dwPutCount = 0;
 m_udtTcpServer.dwSendCount = 0;
 m_udtTcpServer.dwPutTimeCount = 0; 
 m_udtTcpServer.dwSendTimeCount = 0;
 m_udtTcpServer.dwHeartBeatTimeCount = 0;
 
 // 发送缓存区初始化
 m_udtTcpServer.iSendTotalLength = 0;
 // 实时车辆信息包格式:T L 通行信息子包(T-L-V) 特写图子包(T-L-V) 全景图子包(T-L-V)
 memcpy(&m_udtTcpServer.pbtSendBuf[VALUE_ZERO],&TYPE_REALVEHICLE,PACKET_TYPE_LENGTH); // 填充总类型:实时车辆信息 2BYTE
 memcpy(&m_udtTcpServer.pbtSendBuf[PACKET_HEADER_LENGTH],&TYPE_PASSINFO,PACKET_TYPE_LENGTH); // 填充子类型1:车辆信息包 2BYTE
 memcpy(&m_udtTcpServer.pbtSendBuf[PACKET_HEADER_LENGTH+PACKET_TYPE_LENGTH],&PACKET_PASSINFO_LENGTH,PACKET_LENGTH_LENGTH); // 填充子类型1长度:车辆信息子包字节 4BYTE  
 
 // 心跳包格式: T L
 memcpy(&m_udtTcpServer.pbtSendBufHeartBeat[VALUE_ZERO],&TYPE_HEARTBEAT,PACKET_TYPE_LENGTH); // 填充总类型:心跳 2BYTE
 memcpy(&m_udtTcpServer.pbtSendBufHeartBeat[PACKET_TYPE_LENGTH],&PACKET_HEADER_LENGTH,PACKET_LENGTH_LENGTH); // 填充心跳总长度 4BYTE
 
  // 校时包格式: T L V,初始化时复制T L
 memcpy(&m_udtTcpServer.pbtSendBufTime[VALUE_ZERO],&TYPE_TIME,PACKET_TYPE_LENGTH);
 memcpy(&m_udtTcpServer.pbtSendBufTime[PACKET_TYPE_LENGTH],&PACKET_TIME_LENGTH,PACKET_LENGTH_LENGTH);

 InitializeCriticalSection(&m_udtTcpServer.ctsListen); //临界区初始化
 InitializeCriticalSection(&m_udtTcpServer.ctsClient); //临界区初始化
 m_udtTcpServer.evtClientEnd.ResetEvent(); // Sets the state of the event to nonsignaled
 
 if (m_udtTcpServer.bIsDebug)
 {
  WriteToLog(0,"[启动]------------------信息分割线------------------");
 }

 // 建立Socket监听线程
 m_udtTcpServer.threadListen = AfxBeginThread(TcpListenThread, &m_udtTcpServer, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
 m_udtTcpServer.threadListen->m_bAutoDelete = FALSE;
 m_udtTcpServer.threadListen->ResumeThread(); 
 
 m_bInitSuccess = TRUE;

 return VALUE_ZERO;
}

/************************************************************************
Function int GDW_VM2003Server_Send:
    Put data to sendbuffer
Input:
 char* pchDeviceId 设备编号 最多20位 不允许为NULL
 int iRoadWay 车道号
 char* pchPlate 车牌号码 最多20位 不允许为NULL
 char* pchTime 通行时间 最多20位 不允许为NULL
 int iSpeed 车速
 int iSpeedLimit 限速
 DWORD dwDeviceState 设备状态
 int iImageNumber 图片数量
 DWORD dwImageNearSize 特写图片大小 小于等于100K
 BYTE* pbtImageNear 特写图片数据 不允许为NULL
 DWORD dwImageFullSize 全景图片大小 小于等于100K
 BYTE* pbtImageFull 全景图片数据 不允许为NULL
OutPut:
 
return:
 GDW_VM2003Server_Start 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_VM2003Server_Send(char* pchDeviceId,
 int iRoadWay,
 char* pchPlate,
 char* pchTime,
 int iSpeed,
 int iSpeedLimit,
 DWORD dwDeviceState,
 int iImageNumber,
 DWORD dwImageNearSize,
 BYTE* pbtImageNear,
 DWORD dwImageFullSize,
 BYTE* pbtImageFull)
{
 AFX_MANAGE_STATE(AfxGetStaticModuleState());

 DWORD  dwTimeCountInterval; // 时间差值
 int iCursor;
 int iImageNearPacketLength;
 int iImageFullPacketLength;
 
 if (!m_bInitSuccess)
 {
  return -1;
 }

 // 监测线程未启动则直接返回
 if (!m_udtTcpServer.bListenAlive)
 {
  return -101;
 }
 
 // 参数有空指针直接返回
 if ((NULL == pchDeviceId) ||
  (NULL == pchPlate) ||
  (NULL == pchTime) ||
  (NULL == pbtImageNear) ||
  (NULL == pbtImageFull))
 {
  return -2;
 }
 
 // 字符串参数长度超出限制直接返回
 if ((strlen(pchDeviceId) > LIMIT_DEVICEID_LENGTH) ||
  (strlen(pchPlate) > LIMIT_PLATE_LENGTH) ||
  (strlen(pchTime) > LIMIT_PASSTIME_LENGTH))
 {
  return -3;
 }
 
 // 其它参数超出限制直接返回
 if ((dwImageNearSize < LIMIT_MINIMAGESIZE) ||
  (dwImageNearSize > LIMIT_MAXIMAGESIZE) ||
  (dwImageFullSize < LIMIT_MINIMAGESIZE) ||
  (dwImageFullSize > LIMIT_MAXIMAGESIZE) ||
  (iImageNumber < LIMIT_MINIMAGENUMBER) ||
  (iImageNumber > LIMIT_MAXIMAGENUMBER))
 {
  return -4;
 }

 // 不判断客户线程是否已经启动--客户端线程后启动只要不超时即可

 if (m_udtTcpServer.bIsSending) // 正在传输的时候等待足够的时间再尝试
 {
  Sleep(DELAY_WAITSENDING);
  if (m_udtTcpServer.bIsSending)
  {
   WriteToLog("GDW_VM2003Server_Send函数:数据发送中,等待DELAY_WAITSENDING未完成,强制返回!");
   return -5;
  }
 }

 if (m_udtTcpServer.bIsReady) // 上次数据是否还存在
 {
  dwTimeCountInterval = GetTickCount() - m_udtTcpServer.dwPutTimeCount;
  if (dwTimeCountInterval < LIMIT_DATAOVERTIME)
  {
   Sleep(DELAY_WAITSENDING);
   if (m_udtTcpServer.bIsReady)
   {
    if (m_udtTcpServer.bIsDebug)
    {
     WriteToLog(dwTimeCountInterval,"GDW_VM2003Server_Send函数:上次数据未发送,等待DELAY_WAITSENDING仍未发送,强制覆盖!");
    }
   }
  }
 }
 
 // 设置数据尚未准备好标记,客户线程不能读取
 EnterCriticalSection(&m_udtTcpServer.ctsClient);
 m_udtTcpServer.bIsReady = FALSE;
 LeaveCriticalSection(&m_udtTcpServer.ctsClient);
 
 strcpy(m_udtTcpServer.udtPassInfo.pchDeviceId,pchDeviceId);
 strcpy(m_udtTcpServer.udtPassInfo.pchPlate,pchPlate);
 strcpy(m_udtTcpServer.udtPassInfo.pchPassTime,pchTime);

 m_udtTcpServer.udtPassInfo.iRoadWay = iRoadWay;
 m_udtTcpServer.udtPassInfo.iSpeed = iSpeed;
 m_udtTcpServer.udtPassInfo.iSpeedLimit = iSpeedLimit;
 m_udtTcpServer.udtPassInfo.iImageNumber = iImageNumber;
 m_udtTcpServer.udtPassInfo.dwDeviceState = dwDeviceState;
 m_udtTcpServer.udtPassInfo.dwImageNearSize = dwImageNearSize;
 m_udtTcpServer.udtPassInfo.dwImageFullSize = dwImageFullSize;

 iImageNearPacketLength = (int)dwImageNearSize + PACKET_HEADER_LENGTH; // 特写图子包长度
 iImageFullPacketLength = (int)dwImageFullSize + PACKET_HEADER_LENGTH; // 全景图子包长度

 // 往发送缓存区填充内容
 // 实时车辆信息包格式:T L 通行信息子包(T-L-V) 特写图子包(T-L-V) 全景图子包(T-L-V)
 m_udtTcpServer.iSendTotalLength = PACKET_HEADER_LENGTH + PACKET_PASSINFO_LENGTH + iImageNearPacketLength + iImageFullPacketLength;
 // 1-总类型已经填充
 // 2-填充总长度:实时车辆信息 4BYTE
 memcpy(&m_udtTcpServer.pbtSendBuf[PACKET_TYPE_LENGTH],&m_udtTcpServer.iSendTotalLength,PACKET_LENGTH_LENGTH);
 // 3&4-子包1类型、长度已填充
 // 5-子包1数据
 iCursor = PACKET_HEADER_LENGTH * 2;
 memcpy(&m_udtTcpServer.pbtSendBuf[iCursor],&m_udtTcpServer.udtPassInfo,sizeof(m_udtTcpServer.udtPassInfo)); 
 // 6-子包2类型
 iCursor = PACKET_HEADER_LENGTH + PACKET_PASSINFO_LENGTH;
 memcpy(&m_udtTcpServer.pbtSendBuf[iCursor],&TYPE_IMAGENEAR,PACKET_TYPE_LENGTH); 
 // 7-子包2长度
 iCursor += PACKET_TYPE_LENGTH;
 memcpy(&m_udtTcpServer.pbtSendBuf[iCursor],&iImageNearPacketLength,PACKET_LENGTH_LENGTH); 
 // 8-子包2数据
 iCursor += PACKET_LENGTH_LENGTH;
 memcpy(&m_udtTcpServer.pbtSendBuf[iCursor],pbtImageNear,dwImageNearSize); 
 // 9-子包3类型
 iCursor += dwImageNearSize;
 memcpy(&m_udtTcpServer.pbtSendBuf[iCursor],&TYPE_IMAGEFULL,PACKET_TYPE_LENGTH);
 // 10-子包3长度
 iCursor += PACKET_TYPE_LENGTH;
 memcpy(&m_udtTcpServer.pbtSendBuf[iCursor],&iImageFullPacketLength,PACKET_LENGTH_LENGTH);
 // 11-子包3数据
 iCursor += PACKET_LENGTH_LENGTH;
 memcpy(&m_udtTcpServer.pbtSendBuf[iCursor],pbtImageFull,dwImageFullSize); 

 // 设置数据准备好标记,客户线程可以读取
 EnterCriticalSection(&m_udtTcpServer.ctsClient);
 m_udtTcpServer.bIsReady = TRUE;
 m_udtTcpServer.dwPutTimeCount = GetTickCount();
 LeaveCriticalSection(&m_udtTcpServer.ctsClient);
 
 m_udtTcpServer.dwPutCount++;

 return VALUE_ZERO;
}

/************************************************************************
Function int GDW_VM2003Server_Debug:
    Get Debug Info
Input:
 
OutPut:
 WORD* wListenPort 服务器监听的端口号
 int* iListenAlive 监听线程是否存活 1 存活;0 无
 int* iClientAlive 客户处理线程是否存活 1 存活;0 无
 BYTE* pbtClientIp 客户端的IP地址,至少申请4个字节(*.*.*.*),每个字节放一个*
 DWORD* dwDataPutCount 数据有效放入发送区记数
 DWORD* dwDataSendCount 数据有效发送记数
return:
 GDW_VM2003Server_Start 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_VM2003Server_Debug(WORD* wListenPort,
 int* iListenAlive,
 int* iClientAlive,
 BYTE* pbtClientIp,
 DWORD* dwDataPutCount,
 DWORD* dwDataSendCount)
{
 AFX_MANAGE_STATE(AfxGetStaticModuleState());

 if (!m_bInitSuccess)
 {
  return -1;
 }
 
 *wListenPort = m_udtTcpServer.wListenPort;
 if (m_udtTcpServer.bListenAlive)
 {
  *iListenAlive = VALUE_ALIVE;
 }
 else
 {
  *iListenAlive = VALUE_ZERO;
 }
 if (m_udtTcpServer.bClientAlive)
 {
  *iClientAlive = VALUE_ALIVE;
 }
 else
 {
  *iClientAlive = VALUE_ZERO;
 }
 
 if (NULL != pbtClientIp)
 {
  memcpy(pbtClientIp,m_udtTcpServer.btClientIp,sizeof(m_udtTcpServer.btClientIp));
 }
 
 *dwDataPutCount = m_udtTcpServer.dwPutCount;
 *dwDataSendCount = m_udtTcpServer.dwSendCount;

 return VALUE_ZERO;
}

/************************************************************************
Function int GDW_VM2003Server_End:
    End listen thread and client thread
Input:
 
OutPut:
 
return:
 GDW_VM2003Server_Start 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_VM2003Server_End()
{
 AFX_MANAGE_STATE(AfxGetStaticModuleState());

 DWORD dwExitCode;
 DWORD nWaitMilliSecond;
 int iReturn = VALUE_ZERO; // 函数返回值
 int iRetTmp;       
 
 if (!m_bInitSuccess)
 {
  return -1;
 }

 m_udtTcpServer.bIsQuitListen = TRUE;
 m_udtTcpServer.evtClientEnd.SetEvent(); // 通知客户线程终止

 if (m_udtTcpServer.bListenAlive)
 {
  shutdown(m_udtTcpServer.sckListen,SD_BOTH);
  Sleep(DELAY_SHUTDOWNSOCKET);
  closesocket(m_udtTcpServer.sckListen);
  m_udtTcpServer.sckListen = NULL;
 }
  
 if (m_udtTcpServer.bClientAlive)
 {
  shutdown(m_udtTcpServer.sckClient,SD_BOTH);
  Sleep(DELAY_SHUTDOWNSOCKET);
  closesocket(m_udtTcpServer.sckClient);
  m_udtTcpServer.sckClient = NULL;
 }
 
 Sleep(DELAY_SHUTDOWNSOCKET);
 
 nWaitMilliSecond = 0;

 if (m_udtTcpServer.threadListen != NULL)
 {
  for ( ;; )
  {
   iRetTmp = ::GetExitCodeThread(m_udtTcpServer.threadListen->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_udtTcpServer.threadListen->m_hThread,1);
      if (iRetTmp != 0) // 终止监听线程成功
      {
       break;
      }
      else // 终止监听线程失败
      {
       iReturn = -101;
       break;
      }
     }
    }
   }
   else
   {
    break;
   }
  }
 }
 m_udtTcpServer.threadListen = NULL; 

 Sleep(DELAY_WAITQUIT);
 
 if (m_udtTcpServer.bClientAlive)
 {
  iRetTmp = TerminateThread(m_udtTcpServer.threadClient->m_hThread,1000);
  if (0 == iRetTmp)
  {
   iReturn = -102;
  }
 }
 m_udtTcpServer.threadClient= NULL;
 
 DeleteCriticalSection(&m_udtTcpServer.ctsListen); // 删除临界区
 DeleteCriticalSection(&m_udtTcpServer.ctsClient); // 删除临界区

 WSACleanup();
 
 m_bInitSuccess = FALSE;

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

 return iReturn;
}

/************************************************************************
Function int TcpListenThread:
    listen thread
Input:
 UDT_TCPCommunicationServer m_udtTcpServer
OutPut:
 UDT_TCPCommunicationServer m_udtTcpServer
return:
    If no error occurs, returns zero,other returns no zero;
Update:
    Version       Date           Author        Description
    1.0           2008-03-19     Shi Mingjie   Create
************************************************************************/
UINT TcpListenThread(LPVOID pParam)
{
 struct UDT_TCPCommunicationServer *pudtTcpListen = (struct UDT_TCPCommunicationServer *)pParam;

 struct sockaddr_in serverAddr;
 int    iRetTmp = 0;
 int    iLength = 0;
 SOCKET sckAccept = NULL; // 用于临时accept socket
 DWORD  dwWaitCount = 0;   
 int    iErrNumber = 0;
 int    iRetval = 0;
 WORD     wVersion;
 WSADATA  wsaData;

 wVersion = MAKEWORD(1,1);

 iRetval  = WSAStartup(wVersion,&wsaData);
 if (iRetval != 0)
 {
  if (pudtTcpListen->bIsDebug)
  {
   WriteToLog(iRetval,"TcpListenThread线程:没有发现可用的socket通讯库!退出!");
  }
  return -1;
 }

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

 pudtTcpListen->sckListen = socket(AF_INET, SOCK_STREAM, 0);
 if (pudtTcpListen->sckListen == INVALID_SOCKET)
 {
  if (pudtTcpListen->bIsDebug)
  {
   WriteToLog("TcpListenThread线程:socket 函数返回失败!退出!");
  }
  iRetval = WSACleanup();
  if (iRetval == SOCKET_ERROR)
  {
   if (pudtTcpListen->bIsDebug)
   {
    WriteToLog(iRetval,"TcpListenThread线程:WSACleanup失败!退出!");
   }
  }
  return -3;
 }
 
 serverAddr.sin_port = htons(pudtTcpListen->wListenPort);
 serverAddr.sin_family = AF_INET;
 serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
 iRetval = bind(pudtTcpListen->sckListen, (LPSOCKADDR)&serverAddr, sizeof(serverAddr));
 if (iRetval == SOCKET_ERROR)
 {
  if (pudtTcpListen->bIsDebug)
  {
   WriteToLog("TcpListenThread线程:Bind 函数返回失败!退出!");
  }
  return -4;
 }
 
 iLength = sizeof(serverAddr);
 if (getsockname(pudtTcpListen->sckListen,(struct sockaddr *)&serverAddr,&iLength) == SOCKET_ERROR)
 {
  if (pudtTcpListen->bIsDebug)
  {
   WriteToLog("TcpListenThread线程:getsockname 函数返回失败!退出!");
  }
  return -5;
 }

 iRetval = listen(pudtTcpListen->sckListen, LIMIT_MAXLISTENCLIENT);
 if (iRetval == SOCKET_ERROR)
 {
  if (pudtTcpListen->bIsDebug)
  {
   WriteToLog("TcpListenThread线程:listen 函数返回失败!退出!");
  }
  return -6;
 }
 
 pudtTcpListen->bListenAlive = TRUE; // 监听线程状态为存活状态
 if (pudtTcpListen->bIsDebug)
 {
  WriteToLog(0,"TcpListenThread线程:监听成功。");
 }

 for (; ; )
 {
  if (NULL != sckAccept)
  {
   sckAccept = NULL;
  }
  sckAccept = accept(pudtTcpListen->sckListen,(struct sockaddr *)&serverAddr,&iLength);

  if (INVALID_SOCKET == sckAccept)
  {
   if (pudtTcpListen->bIsQuitListen)
   {
    if (pudtTcpListen->bIsDebug)
    {
     WriteToLog(0,"TcpListenThread线程:接收到退出指令。");
    }
    break;
   }
   else
   {
    iErrNumber = WSAGetLastError();
    WriteToLog(iErrNumber,"TcpListenThread线程:没有退出命令时accept 函数返回无效Socket!(记录WSAGetLastError)");
    
    // 2008-03-27 下面这段被注释的代码没有达到预期的作用
    /*****************************************************************
    WriteToLog("TcpListenThread线程:重新监听");
    
    shutdown(pudtTcpListen->sckListen,SD_BOTH);
    Sleep(DELAY_SHUTDOWNSOCKET);
    closesocket(pudtTcpListen->sckListen);
    pudtTcpListen->sckListen = NULL;

    pudtTcpListen->sckListen = socket(AF_INET, SOCK_STREAM, 0);
    if (INVALID_SOCKET == pudtTcpListen->sckListen)
    {
     WriteToLog("TcpListenThread线程:socket 失败!");
    }

    iRetval = bind(pudtTcpListen->sckListen, (LPSOCKADDR)&serverAddr, sizeof(serverAddr));
    if (SOCKET_ERROR == iRetval)
    {
     WriteToLog("TcpListenThread线程:bind 失败!");
    }

    iLength = sizeof(serverAddr);
    if (getsockname(pudtTcpListen->sckListen,(struct sockaddr *)&serverAddr,&iLength) == SOCKET_ERROR)
    {
     WriteToLog("TcpListenThread线程:getsockname 失败!");
    }

    iRetval = listen(pudtTcpListen->sckListen, LIMIT_MAXLISTENCLIENT);
    if (SOCKET_ERROR == iRetval)
    {
     WriteToLog("TcpListenThread线程:listen 失败!");
    }
    *****************************************************************/
   }
  }
  else
  {
   if (pudtTcpListen->bClientAlive)
   {
    pudtTcpListen->evtClientEnd.SetEvent();
    
    if (pudtTcpListen->bIsDebug)
    {
     WriteToLog("TcpListenThread线程:新连接进入时客户线程还存在,销毁!");
    }

    shutdown(pudtTcpListen->sckListen,SD_BOTH);
    Sleep(DELAY_SHUTDOWNSOCKET);
    closesocket(pudtTcpListen->sckListen);
    pudtTcpListen->sckListen = NULL;

    Sleep(DELAY_WAITQUIT * 3);
  
    if (m_udtTcpServer.bClientAlive)
    {
     iRetTmp = TerminateThread(pudtTcpListen->threadClient,1000);
     if (0 == iRetTmp)
     {
      WriteToLog("TcpListenThread线程:TerminateThread 函数销毁client线程失败!");  
     }
    }

    pudtTcpListen->bIsSending = FALSE;
    pudtTcpListen->bClientAlive = FALSE;
    pudtTcpListen->threadClient= NULL;
   }
   else
   {
    if (pudtTcpListen->bIsDebug)
    {
     WriteToLog(0,"TcpListenThread线程:创建新的客户线程。");
    }
   }
   
   pudtTcpListen->sckClient = sckAccept;
   pudtTcpListen->btClientIp[0] = serverAddr.sin_addr.S_un.S_un_b.s_b1;
   pudtTcpListen->btClientIp[1] = serverAddr.sin_addr.S_un.S_un_b.s_b2;
   pudtTcpListen->btClientIp[2] = serverAddr.sin_addr.S_un.S_un_b.s_b3;
   pudtTcpListen->btClientIp[3] = serverAddr.sin_addr.S_un.S_un_b.s_b4;
   
   pudtTcpListen->evtClientEnd.ResetEvent();

   // 建立独立的数据接收处理线程
   pudtTcpListen->threadClient = AfxBeginThread(TcpClientThread, pudtTcpListen, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
   pudtTcpListen->threadClient->m_bAutoDelete = FALSE;
   pudtTcpListen->threadClient->ResumeThread(); 

   Sleep(DELAY_WAITSUCCESS);
   
   if (!pudtTcpListen->bClientAlive) // 如果创建的线程尚未完成启动则等待
   {
    dwWaitCount = 0;
    for (; ; )
    {
     Sleep(DELAY_WAITSUCCESS);
     if (pudtTcpListen->bClientAlive)
     {
      break;
     }
     dwWaitCount++;
     if (DELAY_WAITSUCCESS * dwWaitCount > LIMIT_WAITQUIT)
     {
      if (pudtTcpListen->bIsDebug)
      {
       WriteToLog("TcpListenThread线程:超时未等待到client线程启动成功!");
      }
      break;
     }
    }
   } 
  }

  Sleep(DELAY_WAITSUCCESS);
 }
 
 closesocket(pudtTcpListen->sckListen);
 pudtTcpListen->bListenAlive = FALSE; // 监听线程状态为静止状态
 
 if (pudtTcpListen->bIsDebug)
 {
  WriteToLog(0,"TcpListenThread线程:监听线程关闭。");
 }

 return VALUE_ZERO;
}

/************************************************************************
Function int TcpClientThread:
    client thread
Input:
 UDT_TCPCommunicationServer m_udtTcpServer
OutPut:
 UDT_TCPCommunicationServer m_udtTcpServer
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 TcpClientThread(LPVOID pParam)
{
 struct UDT_TCPCommunicationServer *pudtTcpClient = (struct UDT_TCPCommunicationServer *)pParam;

 int iSendRetval;
 BYTE   pbtReceiveBuf[LIMIT_SENDBUFFERSIZE];
 int    iRealReceive = 0; 
 int    iReceiveRetval = 0;
 short  siType = 0; // 接收到的包类型
 int    iLength = 0; // 接收到的包长度
 DWORD  dwTimeCountInterval; // 时间差值
 
 const long TIMEOUT_RECEIVECHECK = 200000; // 单位为microseconds 微妙
 struct timeval tvReceive={0,TIMEOUT_RECEIVECHECK};  
 fd_set fdReceive;  
 int iSelectRet; // Select函数的返回值
 
 time_t unixTime; // Unix格式时间
 struct tm *tmTime; // tm格式时间
 SYSTEMTIME sysTime;
 int iRet;

 pudtTcpClient->bClientAlive = TRUE;
 if (pudtTcpClient->bIsDebug)
 {
  WriteToLog(0,"TcpClientThread线程:数据处理开始。");
 }

 pudtTcpClient->dwSendTimeCount = GetTickCount(); // 预设为初始发送时间点
 pudtTcpClient->dwHeartBeatTimeCount = GetTickCount(); // 预设为初始心跳时间点

 for (; ;)
 {
  if (WAIT_OBJECT_0 == ::WaitForSingleObject(pudtTcpClient->evtClientEnd.m_hObject, 0))
  {
   if (pudtTcpClient->bIsDebug)
   {
    WriteToLog(0,"TcpClientThread线程:接收到信号量终止指令。");
   }
   break;
  }
  
  // 数据是否已经准备好并发送
  if (pudtTcpClient->bIsReady)
  {
   EnterCriticalSection(&pudtTcpClient->ctsClient);
   pudtTcpClient->bIsSending = TRUE;
   LeaveCriticalSection(&pudtTcpClient->ctsClient);
   
   dwTimeCountInterval = GetTickCount() - pudtTcpClient->dwPutTimeCount;
   if (dwTimeCountInterval > LIMIT_DATAOVERTIME)
   {
    WriteToLog(dwTimeCountInterval,"TcpClientThread线程:超时数据删除不再发送。");
   }
   else
   {
    iSendRetval = send(pudtTcpClient->sckClient,(char *)pudtTcpClient->pbtSendBuf,pudtTcpClient->iSendTotalLength,0);  
    if (SOCKET_ERROR == iSendRetval)
    {
     if (pudtTcpClient->bIsDebug)
     {
      WriteToLog(iSendRetval,"TcpClientThread线程:实时车辆信息发送失败!");
     }
    }
    else
    {
     pudtTcpClient->dwSendCount++;
     if (pudtTcpClient->bIsDebug)
     {
      WriteToLog(iSendRetval,"TcpClientThread线程:实时车辆信息数据发送成功。");
     }
    }
   }

   EnterCriticalSection(&pudtTcpClient->ctsClient);
   pudtTcpClient->bIsSending = FALSE;
   pudtTcpClient->bIsReady = FALSE;
   pudtTcpClient->dwSendTimeCount = GetTickCount();
   LeaveCriticalSection(&pudtTcpClient->ctsClient);
  }
  
  
  // 接收心跳包并回复
  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.  
   pudtTcpClient->evtClientEnd.SetEvent();
   WriteToLog(iSelectRet,"TcpClientThread线程:select 返回SOCKET_ERROR,置退出信号!");
   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,"TcpClientThread线程:recv 返回SOCKET_ERROR,被迫关闭!");
     break;
    }
    else if (VALUE_ZERO == iReceiveRetval) // If the connection has been gracefully closed, the return value is zero.
    {
     pudtTcpClient->evtClientEnd.SetEvent();
     WriteToLog(iReceiveRetval,"TcpClientThread线程:recv 返回VALUE_ZERO,客户端连接完美关闭!");
     break;
    }
    else // If no error occurs, recv returns the number of bytes received.
    {
     siType = 0;
     iLength = 0;

     if (PACKET_HEADER_LENGTH != iReceiveRetval)
     {
      if (pudtTcpClient->bIsDebug)
      {
       WriteToLog(iReceiveRetval,"TcpClientThread线程: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(0,"TcpClientThread线程:接收到心跳包。");
       }
       pudtTcpClient->dwHeartBeatTimeCount = GetTickCount();
       // 回复心跳包
       iSendRetval = send(pudtTcpClient->sckClient,(char *)pudtTcpClient->pbtSendBufHeartBeat,PACKET_HEADER_LENGTH,0);  
       if (SOCKET_ERROR == iSendRetval)
       {
        if (pudtTcpClient->bIsDebug)
        {
         WriteToLog(iSendRetval,"TcpClientThread线程:心跳包发送失败!");
        }
       }
       else
       {
        if (pudtTcpClient->bIsDebug)
        {
         WriteToLog(iSendRetval,"TcpClientThread线程:心跳包发送成功。");
        }
       }
       break;
      case TYPE_TIME: // 时间包
       if (pudtTcpClient->bIsDebug)
       {
        WriteToLog(0,"TcpClientThread线程:接收到校时。");
       }
       iReceiveRetval = recv(pudtTcpClient->sckClient,(char *)&pbtReceiveBuf[iRealReceive],iLength-PACKET_HEADER_LENGTH,0);
       if (SOCKET_ERROR == iReceiveRetval)
       {
        if (pudtTcpClient->bIsDebug)
        {
         WriteToLog("TcpClientThread线程:接收时间数据发生错误!");
        }
        break;
       }
       else if (VALUE_ZERO == iReceiveRetval)
       {
        pudtTcpClient->evtClientEnd.SetEvent();
        WriteToLog(0,"TcpClientThread线程:recv 返回VALUE_ZERO,客户端连接完美关闭!");
        break;
       }
       else
       {
        memcpy(&unixTime,&pbtReceiveBuf[iRealReceive],sizeof(unixTime)); 
        if (pudtTcpClient->bIsDebug)
        {
         WriteToLog(unixTime,"TcpClientThread线程:标准时间。");
        }
        tmTime = gmtime(&unixTime);
        sysTime.wYear = tmTime->tm_year + 1900; // tm struct: current year minus 1900
        sysTime.wMonth = tmTime->tm_mon + 1; // tm struct: Month (0 – 11; January = 0)
        sysTime.wDay = tmTime->tm_mday;
        sysTime.wHour = tmTime->tm_hour;
        sysTime.wMinute = tmTime->tm_min;
        sysTime.wSecond = tmTime->tm_sec;
        sysTime.wMilliseconds = 500;
        
        iRet = SetSystemTime(&sysTime);
        if (VALUE_ZERO == iRet) // 校时失败
        {
         if (pudtTcpClient->bIsDebug)
         {
          WriteToLog("TcpClientThread线程:校时失败!");
         }
        }
        else // 校时成功,返回服务器时间
        {
         if (pudtTcpClient->bIsDebug)
         {
          WriteToLog(iRet,"TcpClientThread线程:校时成功。返回当前服务器时间。");
         }
         time(&unixTime);
         memcpy(&pudtTcpClient->pbtSendBufTime[PACKET_HEADER_LENGTH],&unixTime,sizeof(unixTime));
         // 回复校时包
         iSendRetval = send(pudtTcpClient->sckClient,(char *)pudtTcpClient->pbtSendBufTime,PACKET_TIME_LENGTH,0);  
         if (SOCKET_ERROR == iSendRetval)
         {
          if (pudtTcpClient->bIsDebug)
          {
           WriteToLog(iSendRetval,"TcpClientThread线程:校时成功回复包发送失败!");
          }
         }
         else
         {
          if (pudtTcpClient->bIsDebug)
          {
           WriteToLog(iSendRetval,"TcpClientThread线程:校时成功回复包发送成功。");
          }
         }
        } // end else adjusttime ok
       } // end else receive time packed ok
       break;
      default:
       WriteToLog(siType,"TcpClientThread线程:接收到其它包。");
       break;
      }
     }
    }
   } // end if (FD_ISSET(pudtTcpClient->sckClient,&fdReceive)) 
   else
   {
    if (pudtTcpClient->bIsDebug)
    {
     WriteToLog("TcpClientThread线程:FD_ISSET 返回ZERO!");
    }
   }
   break;
  }  
  
  dwTimeCountInterval = GetTickCount() - pudtTcpClient->dwHeartBeatTimeCount;
  if ((dwTimeCountInterval > LIMIT_HEARTBEAT) && (GetTickCount() > pudtTcpClient->dwHeartBeatTimeCount))
  {
   WriteToLog(dwTimeCountInterval,"TcpClientThread线程:心跳超时,主动退出,等待重连!");
   pudtTcpClient->evtClientEnd.SetEvent();
  }

  Sleep(DELAY_WAITSUCCESS);
 }
 
 shutdown(pudtTcpClient->sckClient,SD_BOTH);
 closesocket(pudtTcpClient->sckClient);

 pudtTcpClient->bIsSending = FALSE;
 pudtTcpClient->bClientAlive  = FALSE;

 return VALUE_ZERO;
}

 

 

你可能感兴趣的:(多线程,socket,header,null,通讯,delay)