//客户端线程,每一个客户链接创建一个线程处理
UINT ClientThread(LPVOID pParam)
{
    myStruct* pMyStruct=(myStruct*)pParam;
    SOCKET sockClient=pMyStruct->Socket;
    HWND hWnd=pMyStruct->hWnd;
    int nRet;
    timeval timeout={0,200};
    fd_set readfds={1,sockClient};
    char szBuf[2049];
    int nRecv;
    while(1)
    {
    nRet=::select(0, &readfds,NULL,NULL,&timeout);//判断是否有数据
    if(nRet>0){
memset(szBuf,0,2049);
nRecv=recv(sockClient,szBuf,2049,0);
char* szTip=new char[64];
memset(szTip,0,64);
sprintf(szTip,"接受到数据!");
::PostMessage(hWnd,WM_ADDLOG,0,(LPARAM)szTip);
         if(nRecv<=0 || nRecv==SOCKET_ERROR )
{
break;//接受数据失败,关闭套接字,关闭线程
}
IN_MSG_HEADER *pHead=(IN_MSG_HEADER*)szBuf;
if(pHead->cmd==MSG_CONNECT_REQ) //请求包
{
IN_REGISTER_REQ* pReq=(IN_REGISTER_REQ*)szBuf;
int nRet1=strncmp(pReq->user,"admin",sizeof("admin"));
int nRet2=strncmp(pReq->password,"admin",sizeof("admin"));
static unsigned int no=0;
if(nRet1==0 && nRet2==0)
{
IN_REGISTER_RESP resp;
resp.hdr.cmd=MSG_CONNECT_RESP;
resp.hdr.length=sizeof(IN_REGISTER_RESP);
resp.hdr.seq_no=no++;
resp.hdr.type=CMD_TYPE_XUNFEI;
resp.result=0;
char* szTip=new char[64];
memset(szTip,0,64);
sprintf(szTip,"用户名密码正确!");
::PostMessage(hWnd,WM_ADDLOG,0,(LPARAM)szTip);
int nSend=send(sockClient,(char*)&resp,sizeof(resp),0);
if(nSend<sizeof(resp))
{
char* szTip=new char[64];
memset(szTip,0,64);
sprintf(szTip,"发送回答数据失败!");
::PostMessage(hWnd,WM_ADDLOG,0,(LPARAM)szTip);
break;//发送数据失败,关闭套接字,关闭线程
}
}
else{
IN_REGISTER_RESP resp;
resp.hdr.cmd=MSG_CONNECT_RESP;
resp.hdr.length=sizeof(IN_REGISTER_RESP);
resp.hdr.seq_no=no++;
resp.hdr.type=CMD_TYPE_XUNFEI;
resp.result=2;
char* szTip=new char[64];
memset(szTip,0,64);
sprintf(szTip,"发送回答用户名密码错误数据!");
::PostMessage(hWnd,WM_ADDLOG,0,(LPARAM)szTip);
int nSend=send(sockClient,(char*)&resp,sizeof(resp),0);
if(nSend<sizeof(resp))
{
char* szTip=new char[64];
memset(szTip,0,64);
sprintf(szTip,"发送回答用户名密码错误数据失败!");
::PostMessage(hWnd,WM_ADDLOG,0,(LPARAM)szTip);
break;//发送数据失败,关闭套接字,关闭线程
}
         break;//非法用户或密码,关闭套接字,关闭线程
}
}
if(pHead->cmd==MSG_EVENT_NOTIFY)
{//正式的接受数据
char* szTip=new char[64];
memset(szTip,0,64);
sprintf(szTip,"接受到报警数据报!");
::PostMessage(hWnd,WM_ADDLOG,0,(LPARAM)szTip);
IN_EVENT_NOTIFY* pNotify=(IN_EVENT_NOTIFY*)szBuf;
int data=pNotify->data;
char description[256];
_snprintf(description,256,pNotify->description);
char syntax[256];
_snprintf(syntax,256,pNotify->syntax);
int type=pNotify->type;
int eventid=pNotify->event_id;
int eventtype=pNotify->evnet_type;
char* szDesc=new char[600];
memset(szDesc,0,600);
char szData[4];
if(data)
sprintf(szData,"报警");
else
sprintf(szData,"恢复"); 
sprintf(szDesc,"联动规则:%s_事件源类型:开关量_开关量:%s_状态:报警事件_描述:%s",syntax,szData,description);
::PostMessage(hWnd,WM_ADDLOG,0,(LPARAM)szDesc);
}
}
/*
if(nRet==SOCKET_ERROR)
{
char* szTip=new char[64];
memset(szTip,0,64);
sprintf(szTip,"socketClient错误!");
::PostMessage(hWnd,WM_ADDLOG,0,(LPARAM)szTip);
break;
}
*/
    }
    closesocket(sockClient);
    return 0; 
}//LoadWinsock用来装载和初始化Winsock,绑定本地地址,创建监听socket,等候客户端连接
UINT LoadWinsock(LPVOID lpParam)
{
CXFServerDlg* pDlg=(CXFServerDlg*)lpParam;

CString strIP;
int nPort=8000;
HWND hWnd;
strIP=pDlg->m_strIP;
nPort=pDlg->m_nPort;
hWnd=pDlg->m_hWnd; sockServer=socket(AF_INET,SOCK_STREAM,0);
if(sockServer==INVALID_SOCKET){
char *szLog=new char[256];
memset(szLog,0,256);
strcpy(szLog,"创建SOCKET失败!");
::PostMessage(hWnd,WM_ADDLOG,0,(LPARAM)szLog);
return 0;
}
SOCKADDR_IN addr;
addr.sin_family=AF_INET;
addr.sin_addr.S_un.S_addr=inet_addr((LPCSTR)strIP);
addr.sin_port=htons(nPort);
if(bind(sockServer,(SOCKADDR*)&addr,sizeof(SOCKADDR))==SOCKET_ERROR){
char *szLog=new char[256];
memset(szLog,0,256);
strcpy(szLog,"SOCKET绑定失败!");
::PostMessage(hWnd,WM_ADDLOG,0,(LPARAM)szLog);
return 0;
}
if(listen(sockServer,5)==SOCKET_ERROR){
char *szLog=new char[256];
memset(szLog,0,256);
strcpy(szLog,"SOCKET监听失败!");
::PostMessage(hWnd,WM_ADDLOG,0,(LPARAM)szLog);
return 0;
}
char *szLog=new char[256];
memset(szLog,0,256);
strcpy(szLog,"开始监听!");
::PostMessage(hWnd,WM_ADDLOG,0,(LPARAM)szLog);
myStruct MyStruct;
    while(1)
{
Sleep(2000);
SOCKADDR_IN addrClient;
int nSize=sizeof(addrClient);
SOCKET sockClient=accept(sockServer,(SOCKADDR*)&addrClient,&nSize);
if(INVALID_SOCKET==sockClient){
char *szLog=new char[256];
memset(szLog,0,256);
strcpy(szLog,"接受SOCKET失败!");
::PostMessage(hWnd,WM_ADDLOG,0,(LPARAM)szLog);
closesocket(sockServer);
return 0; 
}
char* szLog=new char[256];
memset(szLog,0,256);
strcpy(szLog,"开始接受socketClient");
::PostMessage(hWnd,WM_ADDLOG,0,(LPARAM)szLog);
MyStruct.Socket=sockClient;
MyStruct.hWnd=hWnd;
AfxBeginThread(ClientThread,&MyStruct);
}
closesocket(sockServer);
    return 0; 
}
//开始启动服务
void CXFServerDlg::OnBtnStart() 
{
// TODO: Add your control notification handler code here
GetDlgItem(IDC_BTNSTART)->EnableWindow(FALSE);
GetDlgItem(IDC_BTNSTOP)->EnableWindow(TRUE);
UpdateData();
AfxBeginThread(LoadWinsock,this);

}
//显示服务日志
LRESULT CXFServerDlg::OnAddLog(WPARAM wParam,LPARAM lParam)
{
int nLine=m_list.GetCount();
if(nLine>20)
{
for (int i=0;i<nLine;i++)
{
m_list.DeleteString( i );
}
}
char* szLog;
szLog=(LPTSTR)lParam;
m_list.AddString(szLog);
delete[] szLog;
return 0;
}当客户端非法断开链接,怎样关闭套接字和客户线程;这段代码会占用100%的cpu,弄得我都不敢调试了!!

解决方案 »

  1.   

    为什么不用WSAAsyncSelect呢?
    当收到FD_CLOSE后进行处理
      

  2.   

    非法 收不到 close
    心跳信息,你用一个简单的S测试实际上  不一定要非法断开,正常连接的C都要 在长时间不 通信的情况下 K他
      

  3.   

    closesocket()后另一端为什么不能自动检测到,还有如何知道客户线程自动关闭。
      

  4.   

    shutdown(sClient[nnCount], SD_BOTH);  //   通知客户端断开连接
    closesocket(sClient[nnCount]);
      

  5.   

    在引起CPU100%的错误语句前加Sleep()暂停一下就可以避免了。
    我的程序也遇到了你这样的情况,我就这样解决的。
    不知道有没有更好的解决办法。
      

  6.   

    nRecv=recv(sockClient,szBuf,2049,0);
    当nRecv==0时,则说明sockClient已经关闭了。MSDN解释:If no error occurs, recv returns the number of bytes received. If the connection has been gracefully closed, the return value is zero. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling