//这是服务端的代码
DWORD WINAPI AnswerThread(LPVOID lparam) 

IORIsocket ClientSocket;
memcpy(&ClientSocket,lparam,sizeof(IORIsocket));  int bytesRecv; 
char lpBuf[2048];
fd_set fds;
FD_ZERO(&fds);
FD_SET(ClientSocket.client,&fds);
timeval timeout={3,0}; //select等待3秒,3秒轮询,要非阻塞就置0 
while(1) 

int ret=select(0,&fds,NULL,NULL,NULL); // <1> 异常
if (ret==SOCKET_ERROR)
{
break;
} // <2> 无响应:超时
if (ret==0)
{
continue;
} // <3> 有响应:此时为句柄数(应该为1) // 测试sock是否可读,即是否网络上有数据
if(!FD_ISSET(ClientSocket.client,&fds)) 

continue;
}
ZeroMemory(lpBuf,2048);
int iReadCount = recv(ClientSocket.client, lpBuf, 2048, 0);
if(iReadCount == SOCKET_ERROR)
{
int iError = WSAGetLastError(); // 尚未建立连接
if (iError==WSAENOTCONN )
{
continue;
}
// 连接复位:客户端断开连接
if(iError == WSAECONNRESET)
{

//OnDisconnect(iError);
break;
}
// 接收数据过长
if (iError==WSAEMSGSIZE)
{
continue;
}
// 关闭SOCKET
if (iError==WSAEINTR)
{ break;
}
// SOCKET已经关闭
if (iError==WSAENOTSOCK)
{ break;
}
//SendMessage(listHwnd,LB_ADDSTRING,NULL,(LPARAM)lpBuf);
continue;
} // 服务端断开连接:正确接收到空数据
if (iReadCount==0)
{
char tmpStr[1024];
//ZeroMemory(tmpStr,1024);
sprintf(tmpStr,"客户端%s关闭了连接",inet_ntoa(ClientSocket.from.sin_addr));
SendMessage(listHwnd,LB_ADDSTRING,NULL,(LPARAM)tmpStr);
break;
}
//SendMessage(listHwnd,LB_ADDSTRING,NULL,(LPARAM)recvbuf);
if (iReadCount>0)
{
LOG(lpBuf);  //这里写 2进制数据可能有点问题,发送中文的时候就会异常 LOG_BIN()
}

SendMessage(listHwnd,LB_ADDSTRING,NULL,(LPARAM)lpBuf);
send(ClientSocket.client,lpBuf,strlen(lpBuf),0);



char tmpStr[1024];
//ZeroMemory(tmpStr,1024);
sprintf(tmpStr,"%s线程退出",inet_ntoa(ClientSocket.from.sin_addr));
SendMessage(listHwnd,LB_ADDSTRING,NULL,(LPARAM)tmpStr);
return 0; 
} ///////////////////////////////////////////////////////////// 这是客户端的代码
void CSockClientDlg::OnBnClickedButton1()
{
WSADATA wsaData;
SOCKADDR_IN myserver;
memset(&myserver,0,sizeof(SOCKADDR_IN));
int wsaret=WSAStartup(0x101,&wsaData);
if(wsaret!=0)
{
MessageBox("初始化Socket失败","提示",0);
return ;
}
SOCKET clientSocket;
clientSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(clientSocket==INVALID_SOCKET)
{
MessageBox("创建Socket失败","提示",0);
return;
}
CString host;
HOSTENT *hp;
m_EditHost.GetWindowText(host);
if (inet_addr(host.GetString())==INADDR_NONE)
{
hp =gethostbyname(host.GetString());
}else
{
ULONG addr = inet_addr(host.GetString());
hp = gethostbyaddr((char*)&addr,sizeof(addr),AF_INET);
}
if(hp==NULL)
{
// 地址错误
closesocket(clientSocket);
return;
}
myserver.sin_addr.s_addr = *((unsigned long*)hp->h_addr);
myserver.sin_family = AF_INET;
myserver.sin_port = htons(20248);
if(connect(clientSocket,(struct sockaddr*)&myserver,sizeof(myserver)))
{
closesocket(clientSocket);
return; 
}
send(clientSocket,"dssdsdsd",8,0);
closesocket(clientSocket);
WSACleanup();
}
现在我在客户端连接上服务端发送了数据并马上关闭连接。为什么有时候服务端接不到连接关闭的消息有时候可以接到连接关闭的消息?
看图第二次发送请求的时候又收到断开连接的消息了
怎样修改一下可以让服务器每次都能接收到断开的消息?  希望是发完数据后立即断开

解决方案 »

  1.   

    server 端 recv返回0 也是关闭,不必continue 直接break
      

  2.   

    我测试了你的代码,发现大部分情况下服务器能检测到客户端的正常关闭连接,偶尔会出现recv返回失败,错误码为10053的情况,这时代码运行会出现死循环,CPU占用很高。我没有计算出错的概率,也没有找到出错的原因。
      

  3.   

    那这样的话是不是说把
            if(iReadCount == SOCKET_ERROR)
            {
                int iError = WSAGetLastError();            // 尚未建立连接
                if (iError==WSAENOTCONN )
                {
                    continue;
                }
                // 连接复位:客户端断开连接
                if(iError == WSAECONNRESET)
                {    
                    
                    //OnDisconnect(iError);                
                    break;
                }
                // 接收数据过长
                if (iError==WSAEMSGSIZE)
                {
                    continue;
                }
                // 关闭SOCKET
                if (iError==WSAEINTR)
                {                    break;
                }
                // SOCKET已经关闭
                if (iError==WSAENOTSOCK)
                {                break;
                }
                //SendMessage(listHwnd,LB_ADDSTRING,NULL,(LPARAM)lpBuf);
                continue;
            }这段最后这个continue换成break就可以了?
    好像上面superlym2005兄弟也说过 换成break , 不过他说的是 recv返回0 时,他可能是说错位置了,我就没在意