一个项目,server是用vc做的,程序运行后,第一次accept()成功,但客户端断开连接后重新连接的时候accept返回的是无效的socket,而别人用dephi做的客户端却显示连接成功.
server代码如下:
BOOL CMainFrame::InitNet()
{
char buf[200];
::GetCurrentDirectory(200,buf);
strcat(buf,"\\set.ini");
int nPort=GetPrivateProfileInt("Net Set","Net Port",0,buf); WSACleanup();
WSADATA wsaData;
    int iErrorCode;
    if (WSAStartup(MAKEWORD(2,1),&wsaData)) //调用Windows Sockets DLL

         AddToDataList(IDC_ALARMDATA_LIST,"Winsock无法初始化!");
         WSACleanup();
         return FALSE;
} AddToDataList(IDC_ALARMDATA_LIST,"服务器开始创建SOCKET。");
    closesocket(Client);
closesocket(sendClient[0]);
closesocket(sendClient[1]);
closesocket(ServerSocket);
BOOL optval = TRUE;
int err = setsockopt(ServerSocket,SOL_SOCKET,SO_REUSEADDR,(char *)&optval, sizeof(int));
ServerSocket=socket(PF_INET,SOCK_STREAM,0);    //创建服务器端Socket,类型为SOCK_STREAM,面向连接的通信    if(ServerSocket == INVALID_SOCKET)
{
         AddToDataList(IDC_ALARMDATA_LIST,"无法创建服务器socket!");
         return FALSE;
}    m_sockServerAddr.sin_family = AF_INET;
    m_sockServerAddr.sin_addr.s_addr = INADDR_ANY;   //向所有的IP地址发送消息
    m_sockServerAddr.sin_port = htons(nPort);
    
    if (bind(ServerSocket,(LPSOCKADDR)&m_sockServerAddr,sizeof(m_sockServerAddr)) == SOCKET_ERROR) //与选定的端口绑定
    {
        return FALSE;
}    AddToDataList(IDC_ALARMDATA_LIST,"服务器端口:8001.");    iErrorCode=WSAAsyncSelect(ServerSocket,m_hWnd,WM_CLIENT_ACCEPT,FD_ACCEPT);
         // 产生相应传递给窗口的消息为WM_SERVER_ACCEPT ,这是自定义消息    if (iErrorCode == SOCKET_ERROR) 
{
         return FALSE;
}
    if (listen(ServerSocket,5) == SOCKET_ERROR) //开始监听客户连接请求
{
     return FALSE;
}
    bInited=TRUE;
  AddToDataList(IDC_ALARMDATA_LIST,"服务器绑定监听成功。");
    return TRUE; 
}
接收函数:
LRESULT CMainFrame::OnAccept(WPARAM wParam, LPARAM lParam)
{
if (WSAGETSELECTERROR(lParam))
{
return 0L;
}

if(WSAGETSELECTEVENT(lParam) == FD_ACCEPT)//如果
{
SOCKADDR_IN client_addr;
    ZeroMemory(&client_addr, sizeof(client_addr));
    Client = accept(ServerSocket,(LPSOCKADDR)&client_addr,0);
    if (Client == INVALID_SOCKET)
{
return 0L;
}
WSAAsyncSelect(Client,m_hWnd,WM_CLIENT_READCLOSE,FD_READ|FD_CLOSE|FD_OOB|FD_CONNECT);//|FD_QOS|FD_GROUP_QOS|FD_ROUTING_INTERFACE_CHANGE|FD_ADDRESS_LIST_CHANGE);
}

return 0L;
}
关闭连接函数:
LRESULT CMainFrame::OnReadClose(WPARAM wParam, LPARAM lParam)
{
switch (WSAGETSELECTEVENT(lParam))
{
case FD_READ:
break;
case FD_WRITE:
AddToDataList(IDC_ALARMDATA_LIST,"FD_WRITE");
break;
case FD_ACCEPT:
AddToDataList(IDC_ALARMDATA_LIST,"FD_ACCEPT");
break;
case FD_OOB:
AddToDataList(IDC_ALARMDATA_LIST,"FD_OOB");
break;
case FD_CONNECT:
AddToDataList(IDC_ALARMDATA_LIST,"FD_CONNECT");
break;
case FD_CLOSE:
shutdown(Client,2);
closesocket(Client);
break;
}
return 0L;
}

解决方案 »

  1.   

    在Accept的时候检测一下上次的连接是否关闭了,没有的先关闭再连接就没有问题了。
      

  2.   

    试试: 
    SOCKADDR_IN client_addr;
    ZeroMemory(&client_addr, sizeof(client_addr));
    Client = accept(ServerSocket,(LPSOCKADDR)&client_addr,0);
    改为
     SOCKADDR_IN client_addr;
    int addrlen = sizeof(SOCKADDR_IN );
    ZeroMemory(&client_addr, sizeof(client_addr));
    Client = accept(ServerSocket,(LPSOCKADDR)&client_addr,&addrlen ); case FD_CLOSE:
    shutdown(Client,2);
    closesocket(Client);
    改为
     case FD_CLOSE:
    closesocket(Client);
    另外每次新创建一个SOCKET来接受连接,不要用原来的那个。自己维护一个SOCKET的队列。
      

  3.   

    每次都新创建了socket,问题依旧
      

  4.   

    case FD_CLOSE:
    closesocket(Client);Client从哪里来的
    是类成员吧
    如果这样,那这个服务端只能有一个客房端连上来
    同时有两个连上的话会出现问题
      

  5.   

    WM_CLIENT_READCLOSE 是否映射到了 OnReadClose ?
    如果没有,则肯定不会调用closesocket函数了
    还有,你的程序同时只能有一个客户端连上来
      

  6.   

    经过试验 问题细化了一下.. 当客户端连上后,如果什么都不做,退出后再连接就没问题 如果客户端连接上后,我向客户端发送了数据,客户端收到数据后退出 再重新连接服务器 服务器就报错 说在一个非socket套接字上试图操作 晕啊 明明客户端退出的时候我已经关闭了socket了,再进来的时候重新建立的sockt啊
      

  7.   

    用sniffer抓包,看连接和断开时是否有附带数据。
    建议你把不必要的东西去掉,不必要的网络消息不要注册。从最简单作起,慢慢添加功能。
      

  8.   

    设断点调试一下,看有没有调用closesocket函数,关置空(NULL)
    在下次连接时,是否仍用同一套接字,是否为空
      

  9.   

    同意jszj的观点。
    调用closesocket函数后,应将其置空(NULL),下次连接时判断连接是否有效。
    再试试。