网络编程select

来源:互联网 发布:java随机产生10个数 编辑:程序博客网 时间:2024/06/09 22:15

select模型实现了单线程上处理多个套接字的可能

1.select 函数定义如下

int select(

     int nfds;  

     fd_set* readfds;   //指向一个套接字集合

     fd_set* writefds;

     fd_set* exceptfds;  //指向一个套接字集合,用来检查错误

    const struct timeval* timeout    //结构体  指定函数等待的最长时间   如果为NULL 则最长时间为无限长

);

2.套接字集合

fd_set结构可以把多个套接字连在一起,形成一个套接字集合。而select函数可以测试这个集合中哪些套接字有事件发生

typedef struct fd_set{

    u_int fd_count;

   SOCKET fd_array[FD_SETSIZE];   //套接字句柄数组  套接字集合  默认的是64

}fd_set;  

3.操作fd_set的宏

    FD_ZERO(*set)   很显然,初始化set为空集合,集合在使用前应该清空

    FD_CLR(*set)     从set移除套接字s

    FD_ISSET(s,*set)     检查s是不是set的成员,如果是返回TRUE

    FD_SET(s,*set)   添加套接字到集合


主要程序代码:

#include"initsock.h"
#include<stdio.h>

CInitSock theSock;  //初始化Winsock库

int main()
{
    USHORT nPort=4567; //服务器监听的端口
    //创建监听端口
    SOCKET sListen=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    sockaddr_in sin;
    sin.sin_family=AF_INET;
    sin.sin_port=htons(nPort);
    sin.sin_addr.S_un.S_addr=INADDR_ANY;
    //绑定套接字到本地机器
    if(::bind(sListen,(sockaddr*)&sin,sizeof(sin))==SOCKET_ERROR)
    {
        printf("Failed bind()");
        return -1;
    }
    //进入监听模式
    ::listen(sListen,5);

    //select模型处理过程
    //第一步:初始化一个套接字 集合 fdSocket,添加监听套接字句柄到这个集合
    fd_set fdSocket;   //所有可用套接字集合
    FD_ZERO(&fdSocket);
    FD_SET(sListen,&fdSocket);
    while(TRUE)
    {
        //第二步:将fdSocket集合的一个拷贝fdRead传递给select函数
        //当有事件发生时,select函数移除fdRead集合中没有未决I/O操作的套接字句柄,然后返回
        fd_set fdRead=fdSocket;
        int nRet=::select(0,&fdRead,NULL,NULL,NULL);
        if(nRet>0)
        {
            //第三步:通过将原来fdSocket集合与select处理过的fdRead集合比较
            //确定有哪些套接字有未决I/O,并进一步处理这些I/O
            for(int i=0;i<(int)fdSocket.fd_count;i++)
            {
                if(fdSocket.fd_array[i]==sListen) //监听套接字接收到新连接
                {
                    if(fdSocket.fd_count<FD_SETSIZE)
                    {
                        sockaddr_in addrRemote;
                        int nAddrLen=sizeof(addrRemote);
                        SOCKET sNew=::accept(sListen,(SOCKADDR*)&addrRemote,&nAddrLen);
                        FD_SET(sNew,&fdSocket);
                        printf("接收到连接(%s)\n",::inet_ntoa(addrRemote.sin_addr));
                    }
                    else
                    {
                        printf("Too much connections!\n");
                        continue;
                    }
                }
                else
                {
                    char szText[256];
                    int nRecv=::recv(fdSocket.fd_array[i],szText,strlen(szText),0);
                    if(nRecv>0)
                    {
                        szText[nRecv]='\0';
                        printf("接收到数据:%s\n",szText);
                    }
                    else
                    {
                        ::closesocket(fdSocket.fd_array[i]);
                        FD_CLR(fdSocket.fd_array[i],&fdSocket);
                    }
                }
            }
        }
        else
        {
            printf("Failed select()\n");
            break;
        }
    }
    return 0;
}


其中 initsock

#include<WinSock.h>
#pragma comment(lib,"WS2_32")
class CInitSock
{
public:
    CInitSock(BYTE minorVer=2,BYTE majorVer=2)
    {
        //初始化Wsh_32.dll
        WSADATA wsaData;
        WORD sockVersion=MAKEWORD(minorVer,majorVer);
        if(::WSAStartup(sockVersion,&wsaData)!=0)
        {
            exit(0);
        }
    }
    ~CInitSock()
    {
        ::WSACleanup();
    }
};


原创粉丝点击