多線程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->sckClient,SD_BOTH);
    Sleep(DELAY_SHUTDOWNSOCKET);
    closesocket(pudtTcpListen->sckClient);
    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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章