https://blog.csdn.net/men_wen/article/details/53456435

Linux网络编程—I/O复用模型之select

1. IO复用模型

  • IO复用能够预先告知内核,一旦发现进程指定的一个或者多个IO条件就绪,它就通知进程。
  • IO复用阻塞在select或poll系统调用上,而不是阻塞在真正的IO系统调用上。

2. 函数select

select函数能够告知内核对哪些描述符(不局限于套接字)感兴趣以及等待多长事件

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
//返回值:返回就绪描述符数目,若超时则为0, 若出错则为-1
  • timeout用来指定内核等待所指定描述符的任何一个就绪花多长事件。timeval结构用于指定这段事件的秒数和微妙数
struct timeval {long    tv_sec;         /* seconds */long    tv_usec;        /* microseconds */
};
//当timeout为NULL,则永远等待。
//当timeout为timeval,等待固定时间。
//当timeout为timeval,但timeval时间设置为0,则检查描述符字立即返回,称为轮询。
  • 中间的三个参数readfds、writefds、exceptfds指定内核测试读、写、异常条件的描述符,这三个参数都是fd_set结构的指针类型,fd_set结构实现如下:
#define __FD_SETSIZE    1024typedef struct {unsigned long fds_bits[__FD_SETSIZE / (8 * sizeof(long))];
} __kernel_fd_set;

select函数使用描述符集,通常是一个整数数组,其中每一个整数中的每一位对应一个描述符。如何操作这些描述符则系统提供了四个宏

void FD_CLR(int fd, fd_set *set);
//把文件描述符集合里fd清零
int  FD_ISSET(int fd, fd_set *set);
//测试文件描述符集合里fd是否置1
void FD_SET(int fd, fd_set *set);
//把文件描述符集合里fd位置1
void FD_ZERO(fd_set *set);
//把文件描述符集合里所有位清0
  • 如果对应哪一个条件不感兴趣,则可以将它设置为空指针。
  • nfds参数指定待测试的描述符个数,它的值是待测试的最大描述符加1,描述符0到nfds-1都会被测试。
  • select能监听的文件描述符个数受限于FD_SETSIZE,一般为1024,单纯改变进程打开的文件描述符个数并不能改变select监听文件个数。解决1024以下客户端时使用select是很合适的,但如果链接客户端过多,select采用的是轮询模型,会大大降低服务器响应效率。
  • select函数修改由指针readfds、writefds、exceptfds指向的描述符集,调用函数时,我们指定所关心的描述符的值,函数返回时,结果将指示哪些描述符已就绪,函数返回后,使用FD_ISSET宏来测试fd_set数据类型中的描述符,描述符集内任何与未就绪描述符对应的位均清成0.为此,每次重新调用select函数时都要将描述符集内所关心的位置为1。

3. select模型实现

3.1 服务器端

#include "wrap.h"#define MAXLINE         1024int start_ser(char *ipaddr, char *port)
{int sock = Socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in serveraddr;bzero(&serveraddr, sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(port));inet_pton(AF_INET, ipaddr, &serveraddr.sin_addr);Bind(sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr));Listen(sock, 128);return sock;
}int main(int argc, char *argv[])
{int i, maxi, maxfd, listenfd, connfd, sockfd;int nready, client[FD_SETSIZE];ssize_t n;fd_set readset, allset;char buf[MAXLINE];socklen_t clilen;struct sockaddr_in clientaddr;listenfd = start_ser(argv[1], argv[2]); //监听文件描述符maxfd = listenfd;//最大的文件描述符maxi = -1;//数组中最大文件描述符下标for(i = 0; i < FD_SETSIZE; i++){client[i] = -1;}FD_ZERO(&allset);//初始化allset集合FD_SET(listenfd, &allset);//添加监听文件描述符到集合allset中while(1){readset = allset;//每次select都要初始化集合,结构体可以直接赋值nready = select(maxfd+1, &readset, NULL, NULL, NULL);//组摄等待连接或请求if(FD_ISSET(listenfd, &readset)){//当监听文件描述符相应有新的客户端连接时clilen = sizeof(clientaddr);connfd = Accept(listenfd, (struct sockaddr *)&clientaddr, &clilen);//接收该客户端if(connfd < 0){perr_exit("accept err");break;}for(i = 0; i < FD_SETSIZE; i++){if(client[i] < 0){client[i] = connfd;     //保存文件描述符到数组break;}}if(i == FD_SETSIZE){            //连接个数不能大于内核规定的FD_SETSIZEperr_exit("too many clients");}FD_SET(connfd, &allset);//添加新描述符到allset集合中if(connfd > maxfd){maxfd = connfd; //更新最大文件描述符}if(i > maxi){maxi = i;       //更新最大文件描述符下标}if(--nready == 0){      //只有一个listenfd响应则直接跳过下面的语句continue;}}for(i = 0; i <= maxi; i++){     //处理已连接客户端的请求if((sockfd = client[i]) < 0){continue;}if(FD_ISSET(sockfd, &readset)){ //sockfd是否在readset集合中memset(buf, '\0', MAXLINE);if((n = Read(sockfd, buf, MAXLINE-1)) == 0){Close(sockfd);FD_CLR(sockfd, &allset);client[i] = -1;}else{printf("client:%s\n", buf);}if(--nready == 0){//判断是否查找完break;}}}}return 0;
}

3.2 客户端

#include "wrap.h"int main(int argc, char *argv[])
{int connfd;struct sockaddr_in serveraddr;char buf[1024];connfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&serveraddr, sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[2]));inet_pton(AF_INET, argv[1], &serveraddr.sin_addr);Connect(connfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));while(fgets(buf, 1024, stdin) != NULL){Write(connfd, buf, strlen(buf));}Close(connfd);return 0;
}

3.3运行结果

Linux网络编程---I/O复用模型之select相关推荐

  1. Linux网络编程---I/O复用模型之epoll

    https://blog.csdn.net/men_wen/article/details/53456474 Linux网络编程-I/O复用模型之epoll 1. epoll模型简介 epoll是Li ...

  2. Linux网络编程---I/O复用模型之poll

    https://blog.csdn.net/men_wen/article/details/53456474 Linux网络编程-I/O复用模型之poll 1.函数poll poll系统调用和sele ...

  3. 【Linux网络编程学习】I/O多路复用——select和poll

    此为牛客Linux C++课程和黑马Linux系统编程笔记. 0. I/O多路复用 所谓I/O就是对socket提供的内存缓冲区的写入和读出. 多路复用就是指程序能同时监听多个文件描述符. 之前的学习 ...

  4. 第4章 Linux网络编程 24.端口复用

    目录 端口复用 查看网络相关信息的命令 端口复用 端口复用最常用的用途是: 防止服务器重启时之前绑定的端口还未释放 (2msl) 程序突然退出而系统没有释放端口 查看网络相关信息的命令 netstat ...

  5. Linux网络编程 之 IO复用epoll(十)

    1. epoll概述 相对于 select() 和 poll() 来说,epoll 更加灵活,没有描述符限制.epoll 使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个 ...

  6. Linux网络编程——I/O复用之select详解

    https://blog.csdn.net/lianghe_work/article/details/46506143 一.I/O复用概述 I/O复用概念: 解决进程或线程阻塞到某个 I/O 系统调用 ...

  7. Linux网络编程——I/O复用之poll函数

    一.回顾前面的select select优点: 目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点 select缺点: 1.每次调用 select(),都需要把 fd 集合从用户态拷贝到内核 ...

  8. linux 网络7层模型,Linux网络编程——OSI七层模型、TCP/IP模型

    OSI七层模型 开放式系统互连(Open System Interconnect),模型分为7层,从下往上依次为: 物理层: 数据链路层: 网络层: 传输层: 会话层: 表示层: 应用层: 记不住怎么 ...

  9. Linux网络编程——I/O复用函数之epoll

    https://blog.csdn.net/lianghe_work/article/details/46544567 一.epoll概述 epoll 是在 2.6 内核中提出的,是之前的 selec ...

最新文章

  1. Windows魔法堂:解决“由于启动计算机时出现页面文件配置问题.......”
  2. 自动化C语言第一次月考试卷,145班《计算机组成与工作原理》第一次月考试卷...
  3. AtCoder AGC002F Leftmost Ball (DP、组合计数)
  4. MVC后台创建Json(List),前台接受并循环读取
  5. java thread 多线程_java用Thread方式创建多线程
  6. 项目管理中网络图的看法和相关参数阅读说明
  7. “删库跑路”重现江湖,技术和制度如何保障数据安全?
  8. python argparse_Python 命令行之旅——初探 argparse
  9. select模型使用例子
  10. POJ1214 UVA127 Accordian Patience【vector】
  11. python沙箱逃逸小结
  12. js本地存储解决方案(localStorage与userData)
  13. iOS charles 抓包使用
  14. mysql 一对多查询组成单表字段_单表多字段MySQL模糊查询的实现
  15. 用java做一个简易的五子棋
  16. 3D打印Gcode文件命令详解
  17. 像素,分辨率,PPI(像素密度),BPP 扫盲
  18. Glassfish的安装与使用
  19. 山东省第八届 ACM 省赛 Parity check (规律、水)
  20. python_getUniport_从uniport网站中获得指定的字节

热门文章

  1. KnockoutJS-快速入门
  2. EasyRMS录播管理服务器项目实战:windows上开机自启动NodeJS服务
  3. ASP.NET WebAPi之断点续传下载(上)
  4. [Algorithm] 字符串匹配算法——KMP算法
  5. 使用IndexReader.repen提高搜索速度
  6. jenkins修改pom文件_动手实践:美化 Jenkins 报告插件的用户界面
  7. c# 中通快递对接_快递共配是什么?行业前景怎么样?
  8. eclipse mysql生成实体类_Eclipse实现数据库反向生成实体类(pojo)-------(插件安装和实现步骤的说明)...
  9. 二元置信椭圆r语言_医学统计与R语言:圆形树状图(circular dendrogram)
  10. groovy怎样从sql语句中截取表名_Mysql和SQL