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