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 ; \
  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, );
  39. IS_ERROR(listenSock == -);
  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 == -);
  52.  
  53. /*listen port*/
  54. nRet = listen(listenSock, LISTENQ);
  55. IS_ERROR(nRet == -);
  56.  
  57. /*init*/
  58. maxSock = listenSock;
  59. sumSock = -;
  60.  
  61. /*Init socket array*/
  62. for (i=; i<FD_SETSIZE; ++i)
  63. {
  64. clientSock[i] = -;
  65. }
  66.  
  67. /*Init fd_set*/
  68. FD_ZERO(&allset);
  69. FD_SET(listenSock, &allset);
  70.  
  71. /*request*/
  72. while ()
  73. {
  74. rset = allset;
  75. nReady = select(maxSock+, &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=; i<FD_SETSIZE; ++i)
  83. {
  84. if (clientSock[i] < )
  85. {
  86. clientSock[i] = connSock;
  87. break;
  88. }
  89. }
  90.  
  91. if (i == FD_SETSIZE)
  92. {
  93. printf("too many clients!\n");
  94. return ;
  95. }
  96.  
  97. FD_SET(connSock, &allset);
  98.  
  99. maxSock = (maxSock < connSock) ? connSock : maxSock;
  100. sumSock = (sumSock < i) ? i : sumSock;
  101.  
  102. if (--nReady <= )
  103. {
  104. continue;
  105. }
  106. }
  107.  
  108. /*send and recv*/
  109. for (i=; i<=sumSock; ++i)
  110. {
  111. if (clientSock[i] < )
  112. {
  113. continue;
  114. }
  115.  
  116. if (FD_ISSET(clientSock[i], &rset))
  117. {
  118. nRet = recv(clientSock[i], buf, MAXLINE, );
  119.  
  120. if (nRet == || nRet == -)
  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] = -;
  126. }
  127. else if (- == send(clientSock[i], buf, nRet, ))
  128. {
  129. printf("write sock %d err!\n", clientSock[i]);
  130. close(clientSock[i]);
  131. FD_CLR(clientSock[i], &allset);
  132. clientSock[i] = -;
  133. }
  134.  
  135. if (--nReady <= )
  136. {
  137. break;
  138. }
  139. } //if (FD_ISSET(clientSock[i], &rset))
  140. } //for (i=0; i<=sumSock; ++i)
  141. } //while(1)
  142.  
  143. return ;
  144. }

UNIX网络编程-Select模型学习的更多相关文章

  1. UNIX网络编程-Poll模型学习

    1.相关接口介绍 1.1 poll ---------------------------------------------------------------------- #include &l ...

  2. UNIX网络编程——select函数的并发限制和 poll 函数应用举例

    一.用select实现的并发服务器,能达到的并发数,受两方面限制 1.一个进程能打开的最大文件描述符限制.这可以通过调整内核参数.可以通过ulimit -n来调整或者使用setrlimit函数设置,  ...

  3. UNIX网络编程——网络I/O模型

    在学习UNIX网络编程的时候.一開始分不清 同步 和 异步,所以还是总结一下,理清下他们的差别比較好. IO分类 IO依据对IO的调度方式可分为堵塞IO.非堵塞IO.IO复用.信号驱动IO.异步IO. ...

  4. 【unix网络编程第三版】阅读笔记(五):I/O复用:select和poll函数

    本博文主要针对UNP一书中的第六章内容来聊聊I/O复用技术以及其在网络编程中的实现 1. I/O复用技术 I/O多路复用是指内核一旦发现进程指定的一个或者多个I/O条件准备就绪,它就通知该进程.I/O ...

  5. UNIX网络编程——使用select函数编写客户端和服务器

    首先看原先<UNIX网络编程--并发服务器(TCP)>的代码,服务器代码serv.c: #include<stdio.h> #include<sys/types.h> ...

  6. Unix网络编程中的五种I/O模型_转

    转自:Unix网络编程中的的五种I/O模型 下面主要是把unp第六章介绍的五种I/O模型. 1. 阻塞I/O模型 例如UDP函数recvfrom的内核到应用层.应用层到内核的调用过程是这样的:首先把描 ...

  7. 《UNIX网络编程 卷1》之"学习环境搭建"(CentOS 7)

    <UNIX网络编程 卷1>的源码可以从www.unpbook.com下载得到.解压之后的目录为unpv13e. 详细步骤 编译 进入unpv13e目录,按如下步骤编译: ./configu ...

  8. UNIX网络编程 第6章 I/O复用:select和poll函数

    UNIX网络编程 第6章 I/O复用:select和poll函数

  9. 记录一次配置unix网络编程环境的过程和遇到的问题

    记录一次搭建unix网络编程环境过程中遇到的问题和总结 计算机环境虚拟机 linuxmint-18-xfce-64bit 1.打开unix网络编程.iso 把目录下的文件复制到某一目录,修改权限,可命 ...

随机推荐

  1. Spring Application Event Example

    Spring Application Event 项目结构 工程下载 https://github.com/xiaoheike/SpringApplicationEventExample.git Sp ...

  2. Java中的List操作

    1. 数组转List String[] arr={"1","2","3"}; List<String> list = Array ...

  3. netezza 数据库 取 季初 季末 时间

    -- 取季初那一天 select date_trunc( 'quarter',cast('20150820' as date)) -- 取季末那一天 select add_months(date_tr ...

  4. Django 创建APP简单步骤

    yum install epel-releaseyum install python34yum install python-pippip install django django-admin st ...

  5. 启动odoo-10.0成功,但是访问时出错

    启动odoo-10.0显示成功 2017-01-05 06:49:48,211 532 INFO ? odoo: Odoo version 10.02017-01-05 06:49:48,211 53 ...

  6. HTML5学堂,感谢您一年的陪伴(上)

    在HTML学堂将满一周岁之际,感谢再过去的一年里支持和关注它的每一个小伙伴.有了你们的支持,HTML5学堂才能更好的走下去.我们将会把这一年的积累重新体现在HTML5学堂的官网上.HTML5学堂将会全 ...

  7. quick sort 的简化实现

    Pivot 随机选取意义不大 第一种方法使用随机pivot,使得尽可能平均二分序列,而实际上一般来说需要排序的集合往往是乱序的,无需重新生成随机数作为pivot,大可使用固定位置的数作为pivot,这 ...

  8. Android AsyncTask 简单用法

    简介 AsyncTask 是一个轻量级的异步处理类.使用是需继承自该类.可以方便的执行异步任务并且在将进度显示在UI上. 注意事项 AsyncTask只适合处理轻量级的任务即耗时几秒或者几十秒的任务. ...

  9. StackGAN: Text to Photo-realistic Image Synthesis with Stacked Generative Adversarial Networks 论文笔记

    StackGAN: Text to Photo-realistic Image Synthesis with Stacked Generative Adversarial Networks  本文将利 ...

  10. nodemon配置文件简单整理

    文件名称nodemon.json 内容如下: { "restartable":"rs",//重启的命令,默认是 rs "ignore":[& ...