以下是WSAEventSelect模型(服务器),但是,发现了问题:
1.如果客户端不给服务器发送数据,那么,可以正常退出(即,可得到FD_CLOSE事件)
2.如果客户端给服务器发送数据了,而且,客户端使用closesocket退出,在服务器端,却无法正常响应FD_CLOSE。也不知道为什么!有劳各位高人了!谢谢!代码如下:#include "initsock.h"
#include <stdio.h>
#include <winsock2.h>
#pragma  comment(lib,"WS2_32")CInitSock theSock;//加载套接字版本类的对象void main()
{
SOCKET sockArr[WSA_MAXIMUM_WAIT_EVENTS];
WSAEVENT eventArr[WSA_MAXIMUM_WAIT_EVENTS];

WSANETWORKEVENTS networkEvent;
WSAEVENT newEvent;
SOCKADDR_IN netAddr;
SOCKET sockAcpt, sockLstn;

int eventTotal=0;
int index, i;

sockLstn=socket(PF_INET,SOCK_STREAM,0);
netAddr.sin_family=AF_INET;
netAddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
netAddr.sin_port=htons(4567);

bind(sockLstn,(SOCKADDR*)&netAddr,sizeof(netAddr));

newEvent=WSACreateEvent();
WSAEventSelect(sockLstn,newEvent,FD_ACCEPT|FD_CLOSE);

listen(sockLstn,5);

sockArr[eventTotal]=sockLstn;
eventArr[eventTotal]=newEvent;
eventTotal++;

while (TRUE)
{
index=WSAWaitForMultipleEvents(eventTotal,eventArr,FALSE,WSA_INFINITE,FALSE);
index-=WSA_WAIT_EVENT_0;

for (i=index; i<eventTotal; i++)
{
index=WSAWaitForMultipleEvents(1,&eventArr[i],TRUE,0,FALSE);//0,1000
if ((WSA_WAIT_FAILED==index)||(WSA_WAIT_TIMEOUT==index))
{
continue ;
}
else
{
index=i;
WSAEnumNetworkEvents(sockArr[index],eventArr[index],&networkEvent);

if (networkEvent.lNetworkEvents & FD_ACCEPT)//FD_ACCEPT//
{
if (0!=networkEvent.iErrorCode[FD_ACCEPT_BIT])
{
printf("FD_ACCEPT failed with error %d \n",
networkEvent.iErrorCode[FD_ACCEPT_BIT]);
break;
}

sockAcpt=accept(sockArr[index],NULL,NULL);

if (eventTotal>WSA_MAXIMUM_WAIT_EVENTS)
{
printf("Too many connections!");
closesocket(sockAcpt);
break;
}

newEvent=WSACreateEvent();
WSAEventSelect(sockAcpt,newEvent,FD_READ|FD_WRITE|FD_CLOSE);
eventArr[eventTotal]=newEvent;
sockArr[eventTotal]=sockAcpt;
eventTotal++;
printf("Socket %d connected \n",eventTotal);
}
else if (networkEvent.lNetworkEvents & FD_READ)//FD_READ//
{
if (0!=networkEvent.iErrorCode[FD_READ_BIT])
{
printf("FD_READ failed with error %d \n",
networkEvent.iErrorCode[FD_READ_BIT]);
break;
}
printf("FD_READ \n");
char buff[512];
int nRet=::recv(sockArr[index],buff,512,0);
}
else if (networkEvent.lNetworkEvents & FD_WRITE)//FD_WRITE//
{
if (0!=networkEvent.iErrorCode[FD_WRITE_BIT])
{
printf("FD_WRITE failed with error %d \n",
networkEvent.iErrorCode[FD_WRITE_BIT]);
break;
}
printf("FD_WRITE \n");
}
else if (networkEvent.lNetworkEvents & FD_CLOSE)//FD_CLOSE//
{
if (0!=networkEvent.iErrorCode[FD_CLOSE_BIT])
{
printf("FD_CLOSE failed with error %d \n",
networkEvent.iErrorCode[FD_CLOSE_BIT]);
break;
}
closesocket(sockArr[index]);
WSACloseEvent(eventArr[index]);
for (int j=index;j<eventTotal-1;j++)
{
sockArr[j]=sockArr[j+1];
eventArr[j]=eventArr[j+1];
}
eventTotal--;
printf("FD_CLOSE \n");
}
}
}
}
}

解决方案 »

  1.   

    最后的for循环目的是在有客户端退出时将剩下的客户端重新排练吧,不能这样直接赋值排列吧,我记得以前我的程序问题就出在这里,直接赋值排练会出问题,解决方法是建一个空连接链表,将断开的客户端加入空连接链表中,当有新客户端申请连接时从链表中分配端口。
      

  2.   

    (networkEvent.lNetworkEvents & FD_ACCEPT) == FD_ACCEPT 最好用这种写法
      

  3.   

    空连接链表可能他的意思是是用一个链表来保存已经断开连接的客户端socket资源,从链表中分配端口也没看懂,哈哈哈哈
      

  4.   

    我调试了,没问题的。放源码了。
    //#include "initsock.h"
    #include <stdio.h>
    #include <winsock2.h>
    #pragma  comment(lib,"WS2_32")//CInitSock theSock;//加载套接字版本类的对象#define SERVER_PORT 4567void main()
    {
        SOCKET sockArr[WSA_MAXIMUM_WAIT_EVENTS];
        WSAEVENT eventArr[WSA_MAXIMUM_WAIT_EVENTS];
        
        WSANETWORKEVENTS networkEvent;
        WSAEVENT newEvent;
        SOCKADDR_IN netAddr;
        SOCKET sockAcpt, sockLstn;
        
        int eventTotal=0;
        int index, i; // must load socket engine
    WSADATA wd;
    WSAStartup(MAKEWORD(2,2), &wd);
        
        sockLstn=socket(PF_INET,SOCK_STREAM,0);
        netAddr.sin_family=AF_INET;
        netAddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
        netAddr.sin_port=htons(SERVER_PORT); printf("server started success, port = %d\r\n", SERVER_PORT);
        
        bind(sockLstn,(SOCKADDR*)&netAddr,sizeof(netAddr));
        
    // WSAEventSelect will be enabled as you operate for it anywhere
    // and the recently one will take effect instead of the prior one.
        newEvent=WSACreateEvent();
        WSAEventSelect(sockLstn,newEvent,FD_ACCEPT|FD_CLOSE|FD_READ|FD_WRITE);
        
        listen(sockLstn,5);
        
        sockArr[eventTotal]=sockLstn;
        eventArr[eventTotal]=newEvent;
        eventTotal++;
        
        while (TRUE)
        {
            index=WSAWaitForMultipleEvents(eventTotal,eventArr,FALSE,WSA_INFINITE,FALSE);
            index-=WSA_WAIT_EVENT_0;
            
            for (i=index; i<eventTotal; i++)
            {
                index=WSAWaitForMultipleEvents(1,&eventArr[i],TRUE,0,FALSE);//0,1000
                if ((WSA_WAIT_FAILED==index)||(WSA_WAIT_TIMEOUT==index))
                {
                    continue ;
                }
                else
                {
                    index=i;
                    WSAEnumNetworkEvents(sockArr[index],eventArr[index],&networkEvent);
                    
                    if (networkEvent.lNetworkEvents & FD_ACCEPT)//FD_ACCEPT//
                    {
                        if (0!=networkEvent.iErrorCode[FD_ACCEPT_BIT])
                        {
                            printf("FD_ACCEPT failed with error %d \n",
                                networkEvent.iErrorCode[FD_ACCEPT_BIT]);
                            break;
                        }
                        
    SOCKADDR_IN addr;
    int nLen = sizeof(addr);
                        sockAcpt=accept(sockArr[index], (SOCKADDR *)&addr, &nLen);
    printf("Accept client: %s, port: %d\r\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
                        
                        if (eventTotal>WSA_MAXIMUM_WAIT_EVENTS)
                        {
                            printf("Too many connections!");
                            closesocket(sockAcpt);
                            break;
                        }
                        
                        newEvent=WSACreateEvent();
                        WSAEventSelect(sockAcpt,newEvent,FD_READ|FD_WRITE|FD_CLOSE);
                        eventArr[eventTotal]=newEvent;
                        sockArr[eventTotal]=sockAcpt;
                        eventTotal++;
                        printf("Socket %d connected \n",eventTotal);
                    }
                    else if (networkEvent.lNetworkEvents & FD_READ)//FD_READ//
                    {
    printf("FD_READ!\r\n");
                        if (0!=networkEvent.iErrorCode[FD_READ_BIT])
                        {
                            printf("FD_READ failed with error %d \n",
                                networkEvent.iErrorCode[FD_READ_BIT]);
                            break;
                        }
                        printf("FD_READ \n");
                        char buff[512];
                        int nRet=::recv(sockArr[index],buff,512,0);
                    }
                    else if (networkEvent.lNetworkEvents & FD_WRITE)//FD_WRITE//
                    {
    printf("FD_WRITE!\r\n");
                        if (0!=networkEvent.iErrorCode[FD_WRITE_BIT])
                        {
                            printf("FD_WRITE failed with error %d \n",
                                networkEvent.iErrorCode[FD_WRITE_BIT]);
                            break;
                        }
                        printf("FD_WRITE \n");
                    }
                    else if (networkEvent.lNetworkEvents & FD_CLOSE)//FD_CLOSE//
                    {
    printf("FD_CLOSE!\r\n");
                        if (0!=networkEvent.iErrorCode[FD_CLOSE_BIT])
                        {
                            printf("FD_CLOSE failed with error %d \n",
                                networkEvent.iErrorCode[FD_CLOSE_BIT]);
                            break;
                        }
                        closesocket(sockArr[index]);
                        WSACloseEvent(eventArr[index]);
                        for (int j=index;j<eventTotal-1;j++)
                        {
                            sockArr[j]=sockArr[j+1];
                            eventArr[j]=eventArr[j+1];
                        }
                        eventTotal--;
                        printf("FD_CLOSE \n");
                    }
                }
            }
        }
    }