码迷,mamicode.com
首页 > 其他好文 > 详细

UNIX网络编程-Select模型学习

时间:2015-08-19 00:22:25      阅读:95      评论:0      收藏:0      [点我收藏+]

标签:

1、相关接口介绍

1.1 select

----------------------------------------------------------------------

#include <sys/select.h>

#include <sys/time.h>

int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout);

返回:准备好描述字的正数目,0—超时,-1—出错。

----------------------------------------------------------------------

参数说明:

maxfdp1: 制定要检查的描述符的个数,实际应用中传入最大描述符加1,表明要检查0到最大描述符中间的所有描述符。

readset、writeset、exceptset: 这三个参数都是值-结果参数,传入的是应用程序想让内核检查的套接字集合,传出的是内核检查过的可进行操作的套接字集合。

timeout: 超时设置,NULL表示一直等,直到有一个套接字准备好I/O时才返回,将秒和微秒两个字段都设置为0表示不等待,立即返回。

1.2 fd_set

fd_set: 存放套接字的集合。

有四个操作fd_set的宏,分别是:

void FD_ZERO(fd_set *fdset);

void FD_SET(int fd, fd_set *fdset);

void FD_CLR(int fd, fd_set *fdset);

void FD_ISSET(int fd, fd_set *fdset);

FD_SET设置文件描述符集fdset中对应于文件描述符fd的位(设置为1)

FD_CLR清除文件描述符集fdset中对应于文件描述符fd的位(设置为0)

FD_ZERO清除文件描述符集fdset中的所有位(既把所有位都设置为0)。

使用这3个宏在调用select前设置描述符屏蔽位,在调用select后使用FD_ISSET来检测文件描述符集fdset中对应于文件描述符fd的位是否被设置。

1.3 timeval

是一个表示时间的结构体:

1 struct timeval
2 {
3     long tv_sec;   /* seconds */
4     long tv_usec; /* microseconds */
5 };

2、select I/O复用模型的工作流程

2.1 初始化的时候将要检查的socket放入事先定义好的fd_set集合中;

2.2通过调用select函数来获取可读、可写的socket集合;

2.3 获取集合后先检查监听socket,看是否有新的socket连接,若有,则将新的socket添加到集合中准备下一次的扫描;

2.4扫描检查过的集合,对相应的socket进行读写操作;

以下是一个使用select的简单demo,可以处理多个客户端同时跟服务端通信。

3、一个简单的Echo Server

  1 #include <stdio.h>
  2 #include <sys/socket.h>
  3 #include <netinet/in.h>
  4 #include <strings.h>
  5 
  6 #define PORT 8080
  7 #define LISTENQ 5
  8 #define MAXLINE 1024
  9 #define IS_ERROR(condition)  10     if(condition)  11     {  12         printf("Error in func[%s] and line[%d]!\n",  13         __PRETTY_FUNCTION__, __LINE__);  14         return 0;  15     }
 16 
 17 int main(int argc, char *argv[])
 18 {
 19     struct sockaddr_in addrSer;
 20     struct sockaddr_in addrCli;
 21     int listenSock;
 22     int connSock;
 23     int clientSock[FD_SETSIZE];
 24 
 25     int maxSock;     //the max fd
 26     int sumSock;     //sum of client sockets - 1
 27     int nCliLen;       //len of addrCli
 28     int nReady;       //the num of ready sockets
 29 
 30     fd_set allset;
 31     fd_set rset;
 32 
 33     char buf[MAXLINE];
 34     int nRet;
 35     int i;
 36 
 37     /*create listen socket*/
 38     listenSock = socket(AF_INET, SOCK_STREAM, 0);
 39     IS_ERROR(listenSock == -1);
 40 
 41     /*bind listen port*/
 42     bzero(&addrSer, sizeof(addrSer));
 43     addrSer.sin_family      = AF_INET;
 44     addrSer.sin_addr.s_addr = htonl(INADDR_ANY);
 45     addrSer.sin_port        = htons(PORT);
 46     nRet = bind(
 47         listenSock,
 48         (struct sockaddr *)&addrSer,
 49         sizeof(struct sockaddr_in)
 50     );
 51     IS_ERROR(nRet == -1);
 52 
 53     /*listen port*/
 54     nRet = listen(listenSock, LISTENQ);
 55     IS_ERROR(nRet == -1);
 56 
 57     /*init*/
 58     maxSock = listenSock;
 59     sumSock = -1;
 60 
 61     /*Init socket array*/
 62     for (i=0; i<FD_SETSIZE; ++i)
 63     {
 64         clientSock[i] = -1;
 65     }
 66 
 67     /*Init fd_set*/
 68     FD_ZERO(&allset);
 69     FD_SET(listenSock, &allset);
 70 
 71     /*request*/
 72     while (1)
 73     {
 74         rset = allset;
 75         nReady = select(maxSock+1, &rset, NULL, NULL, NULL);
 76 
 77         /*accept*/
 78         if (FD_ISSET(listenSock, &rset))
 79         {
 80             nCliLen = sizeof(addrCli);
 81             connSock = accept(listenSock, (struct sockaddr *)&addrCli, &nCliLen);
 82             for (i=0; i<FD_SETSIZE; ++i)
 83             {
 84                 if (clientSock[i] < 0)
 85                 {
 86                     clientSock[i] = connSock;
 87                     break;
 88                 }
 89             }
 90 
 91             if (i == FD_SETSIZE)
 92             {
 93                 printf("too many clients!\n");
 94                 return 0;
 95             }
 96 
 97             FD_SET(connSock, &allset);
 98 
 99             maxSock = (maxSock < connSock) ? connSock : maxSock;
100             sumSock = (sumSock < i) ? i : sumSock;
101 
102             if (--nReady <= 0)
103             {
104                 continue;
105             }
106         }
107 
108         /*send and recv*/
109         for (i=0; i<=sumSock; ++i)
110         {
111             if (clientSock[i] < 0)
112             {
113                 continue;
114             }
115 
116             if (FD_ISSET(clientSock[i], &rset))
117             {
118                 nRet = recv(clientSock[i], buf, MAXLINE, 0);
119 
120                 if (nRet == 0 || nRet == -1)
121                 {
122                     printf("read sock %d err, nRet = %d!\n", clientSock[i], nRet);
123                     close(clientSock[i]);
124                     FD_CLR(clientSock[i], &allset);
125                     clientSock[i] = -1;
126                 }
127                 else if (-1 == send(clientSock[i], buf, nRet, 0))
128                 {
129                     printf("write sock %d err!\n", clientSock[i]);
130                     close(clientSock[i]);
131                     FD_CLR(clientSock[i], &allset);
132                     clientSock[i] = -1;
133                 }
134 
135                 if (--nReady <= 0)
136                 {
137                     break;
138                 }
139             } //if (FD_ISSET(clientSock[i], &rset))
140         } //for (i=0; i<=sumSock; ++i)
141     } //while(1)
142 
143     return 0;
144 }

 

UNIX网络编程-Select模型学习

标签:

原文地址:http://www.cnblogs.com/mhscn/p/4740858.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!