1. 程式人生 > >多執行緒TCP/IP通訊的服務端

多執行緒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;
}