📄 networkthread.cpp
字号:
// NetWorkThread.cpp: implementation of the CNetWorkThread class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ChenMiddleware.h"
#include "NetWorkThread.h"
#include "Get_CheckSum.h"
#include "DataBase.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define PACKETlEN_FIELD_VALUE 4
#define PROTOCAL_FIELD_VALUE 4
CDB g_db;
extern HANDLE g_hEventEnd;
extern bool bThreadExitFlag;
extern char g_ServerIp[16];
extern int g_ListenPort;
extern CStatic *g_Static_Tishi1;
extern CListCtrl *g_pListBox_Main;
extern CGetCheckSum g_CheckSum;
WSAEVENT g_eventArray[WSA_MAXIMUM_WAIT_EVENTS]; //存放事件对象全局数组
SOCKET g_sockArray[WSA_MAXIMUM_WAIT_EVENTS]; //存放Socket句柄的数组
int g_nEventTotal = 0; //记录事件对象总数
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CNetWorkThread::CNetWorkThread()
{
}
CNetWorkThread::~CNetWorkThread()
{
}
bool CNetWorkThread::GetString(SOCKET hSocket, char *recBuf, int recBufSize)
{
int ret,nLeft,idx,flag=1,icount=0;
nLeft=recBufSize;
idx=0;
while(nLeft>0)
{
ret=recv(hSocket,&recBuf[idx],nLeft,0);
if(ret==SOCKET_ERROR || ret==0 || ret==WSAETIMEDOUT) //套接字出错或者已经关闭或超时
{
flag=0;
break;
}
idx+=ret;
nLeft-=ret;
}
//返回判断
if(flag==0)
{
TRACE1("recv errorcode: %d",ret);
TRACE1("WSAGetLastError(): %d",WSAGetLastError());
return false;
}
else
//TRACE1("recv num: %d",ret);
return true;
//if no data arrives within the period specified in SO_RCVTIMEO
//the recv function returns WSAETIMEDOUT,
//and if data is received, recv returns SUCCESS.
}
bool CNetWorkThread::SendString(SOCKET m_hSocket, char *buf, int length)
{
int nLeft,idx,ret,flag=1;
nLeft=length;
idx=0;
while(nLeft>0) //确保完全发送出去
{
ret=send(m_hSocket,&buf[idx],nLeft,0);
if(ret==SOCKET_ERROR)
{
flag=0;
break;
}
nLeft-=ret;
idx+=ret;
}
//返回判断
if(flag==0)
return false;
else
return true;
}
void CNetWorkThread::CreateThread()
{
m_pThread=AfxBeginThread(ServiceFunction, this, THREAD_PRIORITY_NORMAL, 0, 0, NULL );
}
UINT CNetWorkThread::ServiceFunction(LPVOID pParam)
{
//TRACE0("ServiceFunction(LPVOID pParam)");
CNetWorkThread * pThread=(CNetWorkThread *)pParam;
pThread->Run();
return 1;
}
int CNetWorkThread::Run()
{
//TRACE0("CNetWorkThread::Run()");
WSADATA wsa;
m_hListen=NULL;
WSAEVENT event0;
char cHostName[255]="";
char revbuf[1024]; //接收buf
SYSTEMTIME stLocal;
CString CurDateStr;
sockaddr_in remoteAddr;
int nAddrLen = sizeof(remoteAddr);
CString iItemStr;
int iItemIndex=0;
if(WSAStartup(MAKEWORD(2, 2), &wsa) == SOCKET_ERROR)
return 1;
if(LOBYTE(wsa.wVersion) != 2 || HIBYTE(wsa.wVersion) != 2)
goto CLEANUP;
if(::gethostname(cHostName,255)!=0) //主机的机器名
{
MessageBox(NULL,"获取机器名出错!系统将关闭","警告",MB_ICONWARNING|MB_OK );
return 0;
}
if(g_db.ConnectDB(cHostName,"STUDENTS","sa","00abcdly")==false)
{
MessageBox(NULL,"数据库连接失败","警告",MB_ICONWARNING|MB_OK );
return 0;
}
TRACE0("数据库连接成功");
SOCKADDR_IN sockAddr;
memset(&sockAddr, 0, sizeof(sockAddr));
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr = INADDR_ANY;//inet_addr(g_ServerIp);
sockAddr.sin_port = htons(g_ListenPort);
m_hListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(m_hListen == INVALID_SOCKET)
{
TRACE0("WSASocket: INVALID_SOCKET return");
goto CLEANUP;
}
if(bind(m_hListen, (sockaddr*)&sockAddr, sizeof(sockAddr) ) == SOCKET_ERROR)
{
TRACE0("bind: Bind error");
goto CLEANUP;
}
if(listen(m_hListen, 5) == SOCKET_ERROR)
{
TRACE0("Listen: listen error");
goto CLEANUP;
}
TRACE0("Listen...");
// 创建事件对象,并关联到新的套节字
event0 = ::WSACreateEvent();
::WSAEventSelect(m_hListen, event0, FD_ACCEPT|FD_CLOSE);
// 添加到表中
g_eventArray[g_nEventTotal] = event0;
g_sockArray[g_nEventTotal] = m_hListen;
g_nEventTotal++;
while(1)
{
if(bThreadExitFlag==true)
{
bThreadExitFlag=false;
TRACE0("正在停止服务...... ");
for(int k=0;k<g_nEventTotal;k++)
{
closesocket(g_sockArray[k]);
g_sockArray[k]=NULL;
}
WSACleanup();
g_db.CloseDatabase();
SetEvent(g_hEventEnd); //设置为有信号
Sleep(10);
return 0;
}
//在所有事件对象上等待, 正常返回第n号事件的顺序值,如0,1,2,...
int nIndex = ::WSAWaitForMultipleEvents(g_nEventTotal, g_eventArray, FALSE, 10, FALSE);
if(nIndex == WSA_WAIT_FAILED || nIndex == WSA_WAIT_TIMEOUT)
{
continue;
}
//TRACE("nIndex1=%d",nIndex);
// 对每个事件调用WSAWaitForMultipleEvents函数,以便确定它的状态
nIndex = nIndex - WSA_WAIT_EVENT_0;
for(int i=nIndex; i<g_nEventTotal; i++)
{
nIndex = ::WSAWaitForMultipleEvents(1, &g_eventArray[i], TRUE, 10, FALSE);
if(nIndex == WSA_WAIT_FAILED || nIndex == WSA_WAIT_TIMEOUT)
{
continue;
}
else
{
//TRACE("nIndex2=%d",nIndex);
// 获取到来的通知消息,WSAEnumNetworkEvents函数会自动重置受信事件
WSANETWORKEVENTS event;
::WSAEnumNetworkEvents(g_sockArray[i], g_eventArray[i], &event);
if(event.lNetworkEvents & FD_ACCEPT) // 处理FD_ACCEPT通知消息
{
if(event.iErrorCode[FD_ACCEPT_BIT] == 0)
{
if(g_nEventTotal > WSA_MAXIMUM_WAIT_EVENTS)
{
TRACE0("Too many connections! ");
continue;
}
SOCKET sNew = ::accept(g_sockArray[i], (SOCKADDR*)&remoteAddr, &nAddrLen);
//这里可以加入身份认证,拒绝非法用户。
::GetLocalTime(&stLocal);
CurDateStr.Format("%u-%02u-%02u %02u:%02u:%02u", stLocal.wYear, stLocal.wMonth, stLocal.wDay,stLocal.wHour,stLocal.wMinute,stLocal.wSecond);
if(g_pListBox_Main->GetItemCount()>=200)
{
g_pListBox_Main->DeleteAllItems();
iItemIndex=0;
}
iItemStr.Format("%d",iItemIndex+1);
g_pListBox_Main->InsertItem(iItemIndex,iItemStr);
g_pListBox_Main->SetItemText(iItemIndex,1,CurDateStr);
g_pListBox_Main->SetItemText(iItemIndex,2,inet_ntoa(remoteAddr.sin_addr));
//g_pListBox_Main->SetItemText(iItemIndex,3,"");
iItemIndex++;
WSAEVENT event = ::WSACreateEvent();
::WSAEventSelect(sNew, event, FD_READ|FD_CLOSE|FD_WRITE);
// 添加到表中
g_eventArray[g_nEventTotal] = event;
g_sockArray[g_nEventTotal] = sNew;
g_nEventTotal++;
}
}
else if(event.lNetworkEvents & FD_READ) // 处理FD_READ通知消息
{
if(event.iErrorCode[FD_READ_BIT] == 0)
{
//这里接收通信数据,解密,并处理。成功的话向客户返回消息。
ZeroMemory(revbuf,1024);
int iPacetLength;
char cRet;
char sendbuf[11]="#*********";
bool nRecv1=false,nRecv2=false;
char NewCheckSum[9]="",OldCheckSum[9]="";
char protocal[PROTOCAL_FIELD_VALUE+1]="";
nRecv1 =GetString(g_sockArray[i], revbuf,PACKETlEN_FIELD_VALUE);
if(nRecv1)
{
revbuf[PACKETlEN_FIELD_VALUE]=0;
iPacetLength=atoi(revbuf);
TRACE1("接收到数据头部长度字段: %d",iPacetLength);
nRecv2=GetString(g_sockArray[i], revbuf+PACKETlEN_FIELD_VALUE, iPacetLength-PACKETlEN_FIELD_VALUE);
if(nRecv2)
{
TRACE1("接收到数据:%s", revbuf);
//NO1: 得到传过来的原始校验和值
strncpy(OldCheckSum,revbuf+iPacetLength-8,8);
OldCheckSum[8]=0;
//NO2: 计算校验和,并检验
g_CheckSum.Get_CheckSum(revbuf,iPacetLength,NewCheckSum);
TRACE2("OldCheckSum=%s,NewCheckSum=%s",OldCheckSum,NewCheckSum);
if(strcmp(NewCheckSum,OldCheckSum)!=0)
cRet='3'; //校验和错误
else
{
strncpy(protocal,revbuf+PACKETlEN_FIELD_VALUE,PROTOCAL_FIELD_VALUE);//提取协议字段值
protocal[PROTOCAL_FIELD_VALUE]=0;
cRet=DoPacket(protocal,revbuf+PACKETlEN_FIELD_VALUE+PROTOCAL_FIELD_VALUE,iPacetLength-PACKETlEN_FIELD_VALUE-PROTOCAL_FIELD_VALUE);
}
//构造返回数据,生成校验并发送
sendbuf[0]=cRet;
g_CheckSum.Get_CheckSum(sendbuf,strlen(sendbuf),NewCheckSum);
SendString(g_sockArray[i],sendbuf,10);
}
}
if(nRecv1==false || nRecv2==false) //nRecv= 0 or SOCKET_ERROR
{
TRACE0("beacuse: nRecv= 0 or SOCKET_ERROR. so call: closesocket,WSACloseEvent");
::closesocket(g_sockArray[i]);
WSACloseEvent(g_eventArray[i]);
for(int j=i; j<g_nEventTotal-1; j++)
{
g_eventArray[j] = g_eventArray[j+1];
g_sockArray[j] = g_sockArray[j+1];
}
g_nEventTotal--;
}
}
}//end else if
else if(event.lNetworkEvents & FD_CLOSE) // 处理FD_CLOSE通知消息
{
TRACE0("FD_CLOSE: closesocket,WSACloseEvent");
::closesocket(g_sockArray[i]);
WSACloseEvent(g_eventArray[i]);
for(int j=i; j<g_nEventTotal-1; j++)
{
g_eventArray[j] = g_eventArray[j+1];
g_sockArray[j] = g_sockArray[j+1];
}
g_nEventTotal--;
}
else if(event.lNetworkEvents & FD_WRITE) // 处理FD_WRITE通知消息
{
TRACE0("FD_WRITE通知消息,有客户进入");
}
}
}//end for
}//end while(1)
CLEANUP:
if(m_hListen != NULL) //关掉监听socket
{
closesocket(m_hListen);
m_hListen=NULL;
}
g_Static_Tishi1->SetWindowText(" 警告:启动失败. 请点击‘停止服务’按钮!");
WSACleanup();
TRACE0("未启动");
return 1;
}
//处理请求包
char CNetWorkThread::DoPacket(char portocalchar[], char packet[], int iPacketLen)
{
char ret;
switch (atoi(portocalchar))
{
case 1:
ret=m_DopacketObj.AddStudents(packet,iPacketLen);
break;
case 2:
break;
}
return ret;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -