网络编程之select模式

来源:互联网 发布:mysql 清空整个数据库 编辑:程序博客网 时间:2024/05/20 18:00

select模式是一个广泛在Winsock中使用的I/O模式,这个模式的设计源于UNIX系统

主要使用select函数管理,故称之为select模式

select函数可以判断套接字是否存在数据,或者是否可以写入数据

select Function

 The select function determines the status of one or more sockets, waiting if necessary, to perform synchronous I/O.

int select(  __in          int nfds, //this is parameter can ignore. set to 0.  __in_out      fd_set* readfds,    //Optional pointer to a set of sockets to be checked for readability.  __in_out      fd_set* writefds,   //Optional pointer to a set of sockets to be checked for writability.  __in_out      fd_set* exceptfds,  //Optional pointer to a set of sockets to be checked for errors.  __in          const struct timeval* timeout    //Maximum timer for select to wait.Set timeout parameter to NULL for blocking operations.);

Return Value

The select function return the total parameter number of socket handles that are ready and contained in the fd_set structure.


fd_set Structure

The fd_set structure is used by various Windows Sockets functions and service providers,  such as the select function, to place sockets into a "set" for various purposes, such as testing a given socket for readability using thereadfds parameter of the select function.

typedef struct fd_set {  u_int fd_count;  //Number of sockets in the set.  SOCKET fd_array[FD_SETSIZE];  //Array of sockets that are in the set.} fd_set;
操作fd_set的几个宏:

●    FD_ZERO(*set)         初始化set为空集合。集合在使用前应该总是清空

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

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

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


使用select模式的步骤:

1.    加载套接字: WSAStartup();

2.    创建套接字;socket()

3.    绑定本地地址到套接字:bind();

4.    侦听:listen();

5 .   进入循环

6.    声明并初始化一个套接字集合,向这个套接字添加监听套接字句柄

7.    使用select函数移除该套接字集合没有发生I/O活动的套接字

8.    处理发生活动的I/O

9.    返回第6步


以下是Server代码

#include <winsock2.h>#include <iostream>#pragma comment(lib, "WS2_32")using namespace std;int main(){WSADATA wsadata; if(0 != ::WSAStartup(MAKEWORD(2, 2), &wsadata))   //load socket, and set it's version.{cout<<"WSAStartup() -- FAILED"<<endl;WSACleanup();return -1;}SOCKET s = socket(AF_INET, SOCK_STREAM, 0);    //create socket.if(INVALID_SOCKET == s){cout<<"socket() -- FAILED"<<endl;WSACleanup();return -1;}sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port   = htons(4567);sin.sin_addr.S_un.S_addr   = INADDR_ANY;if(SOCKET_ERROR == bind(s, (sockaddr*)&sin, sizeof(sin)))    //bind socket{cout<<"bind() -- FAILED"<<endl;WSACleanup();return -1;}::listen(s, 10); while(true){fd_set fdSet;FD_ZERO(&fdSet);FD_SET(s, &fdSet);    //add s to fdSetint nLen = ::select(0, &fdSet, NULL, NULL, NULL);   //Remove not active I/Oif(0 < nLen){for(int i=0; i<(int)fdSet.fd_count; ++i){if(FD_ISSET(fdSet.fd_array[i], &fdSet)){sockaddr_in addr;int len = sizeof(addr);SOCKET sock = ::accept(s, (sockaddr*)&addr, &len);FD_SET(sock, &fdSet);cout<<"New connect:%d"<<inet_ntoa(addr.sin_addr)<<endl;}else{char szTex[256];int txtLen = ::recv(fdSet.fd_array[i], szTex, sizeof(szTex), 0);if(0 < txtLen){cout<<szTex<<endl;}else{closesocket(fdSet.fd_array[i]);FD_CLR(fdSet.fd_array[i], &fdSet);}}}}else{cout<<"Fail connect"<<endl;Sleep(2000);}}closesocket(s);WSACleanup();return 0;}


原创粉丝点击