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

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运行结果

这里写图片描述

这里写图片描述

这里写图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383761.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

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

https://blog.csdn.net/men_wen/article/details/53456474Linux网络编程—I/O复用模型之poll 1.函数poll poll系统调用和select类似&#xff0c;也是在指定时间内轮询一定数量的文件描述符&#xff0c;以测试其中是否有就绪者。 #include <poll.h>int poll(struct pollfd…

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

https://blog.csdn.net/men_wen/article/details/53456474 Linux网络编程—I/O复用模型之epoll 1. epoll模型简介 epoll是Linux多路服用IO接口select/poll的加强版&#xff0c;e对应的英文单词就是enhancement&#xff0c;中文翻译为增强&#xff0c;加强&#xff0c;提高&…

POJ 1741tree-点分治入门

学习了一下点分治&#xff0c;如果理解有误还请不吝赐教。 为了快速求得树上任意两点之间距离满足某种关系的点对数&#xff0c;我们需要用到这种算法。 点分治是树上的一种分治算法&#xff0c;依靠树和子树之间的关系进行分治从而降低复杂度。 和其他树上的算法有一些区别…

基于单链表的生产者消费者问题

『生产者与消费者问题分析』「原理」生产者生产产品&#xff0c;消费者消费产品。产品如果被消费者消费完了&#xff0c;同时生产者又没有生产出产品&#xff0c;消费者 就必须等待。同样的&#xff0c;如果生产者生产了产品&#xff0c;而消费者没有去消费&#x…

C++智能指针(二)模拟实现三种智能指针

https://blog.csdn.net/nou_camp/article/details/70186721在上一篇博客中提到了Auto_ptr(C智能指针&#xff08;一&#xff09;)&#xff0c;下面进行模拟实现Auto_ptr 采用类模板实现 #include<iostream> using namespace std; template<class T> class Autoptr …

C++智能指针(三)总结

https://blog.csdn.net/nou_camp/article/details/70195795 在上一篇博客中&#xff08;C智能指针&#xff08;二&#xff09;&#xff09;模拟实现了三种智能指针。 其中最好的就是shared_ptr,但是这并不代表它就是最完美的&#xff0c;它也有问题&#xff0c;这个问题就是循环…

c++11 你需要知道这些就够了

https://blog.csdn.net/tangliguantou/article/details/50549751c11新特性举着火把寻找电灯今天我就权当抛砖引玉&#xff0c;如有不解大家一起探讨。有部分内容是引用自互联网上的内容&#xff0c;如有问题请联系我。T&& 右值引用 std::move 右值引用出现之前我们只能…

c++仿函数 functor

https://www.cnblogs.com/decade-dnbc66/p/5347088.html内容整理自国外C教材先考虑一个简单的例子&#xff1a;假设有一个vector<string>&#xff0c;你的任务是统计长度小于5的string的个数&#xff0c;如果使用count_if函数的话&#xff0c;你的代码可能长成这样&#…

Ubuntu软件更新失败

刚安装好Ubuntu以后需要将系统的软件都更新一下&#xff0c;但是遇到一个问题就是下载仓库信息失败&#xff0c;大概是这个样子的错误&#xff1a; 经国遇到这样的问题可以试一下下面这个命令&#xff1a; sudo rm -rf /var/lib/apt/lists/* sudo apt-get update参考网址&…

getsockname函数与getpeername函数的使用

https://www.tuicool.com/articles/V3Aveygetsockname和getpeername函数 getsockname函数用于获取与某个套接字关联的本地协议地址 getpeername函数用于获取与某个套接字关联的外地协议地址 定义如下&#xff1a;[cpp] view plaincopy#include<sys/socket.h> int gets…

Linux命令【一】基本命令

shell命令和bash命令相同&#xff0c;指的是命令解析器 快捷键 history 所有的历史命令ctrl P 向上滚动命令 ctrl N 向下滚动命令 ctrlB将光标向前移动 ctrlF将光标向后移动 ctrlA移动到命令行头部 ctrlE移动到命令行尾部 光标删除操作&#xff1a;删除光标前面字符ctrlh或…

剑指offer面试题:替换空格

https://blog.csdn.net/yanxiaolx/article/details/52235212题目&#xff1a;请实现一个函数&#xff0c;把字符串中的每个空格替换成“%20”。例如输入“We are happy.”&#xff0c;则输出“We%20are%20happy.”。解析&#xff1a;时间复杂度为O(n)的解法。完整代码及测试用例…

数据库原理及应用【一】引言

什么是数据库&#xff1a;一个大规模的集成的数据集合 作用&#xff1a;描述现实世界的实体(entities)以及实体之间的关系 管理数据库的系统软件&#xff1a;DBMS 文件是一个平滑的字符流&#xff0c;无法完成信息的检索和管理 数据&#xff08;data&#xff09;:用来描述现…

用c++模拟实现一个学生成绩管理系统

https://blog.csdn.net/yanxiaolx/article/details/53393437题目&#xff1a;用c模拟实现一个学生成绩的信息管理系统&#xff0c;要求能添加、删除、修改、查看和保存学生的信息等功能 源代码如下:[cpp] view plaincopy#define _CRT_SECURE_NO_WARNINGS #include<iostr…

Python3列表

操作&#xff1a;索引、切片、加、乘、检查成员、确定序列长度、确定最大最小元素 定义&#xff1a; 列表名 [元素]下标列表名[x] 截取:列表名[x:y] 更新&#xff1a; list[x]y 或者使用append()方法添加列表项删除&#xff1a; del list[x]常用操作&#xff1a; 截取与…

Linux惊群效应详解(最详细的了吧)

https://blog.csdn.net/lyztyycode/article/details/78648798?locationNum6&fps1 linux惊群效应详细的介绍什么是惊群&#xff0c;惊群在线程和进程中的具体表现&#xff0c;惊群的系统消耗和惊群的处理方法。1、惊群效应是什么&#xff1f;惊群效应也有人叫做雷鸣群体效应…

epoll原理详解(最清晰)

https://blog.csdn.net/lyztyycode/article/details/79491419我只是把内容搬运过来做个记录&#xff0c;方便自己以后回头看。第一部分&#xff1a;select和epoll的任务关键词&#xff1a;应用程序 文件句柄 用户态 内核态 监控者要比较epoll相比较select高效在什么地方&#x…

Ubuntu卸载软件

用过使用dpkg软件管理工具得到所有已经安装的软件&#xff0c;如果不清楚软件的全名可以使用grep命令进行查找 然后再使用sudo apt-get remove --purge 软件名卸载软件&#xff08;--purge参数会删除配置文件&#xff0c;删的干净一些&#xff09; 例如&#xff1a;

一个重要且实用的signal---SIGCHLD

https://blog.csdn.net/lyztyycode/article/details/78150805SIGCHLD(修改)因为笔者之前的文章里面有错误&#xff0c;今天发现&#xff0c;立马做个修改。在下面我的一段关于sigchld信号相对于直接调用wait函数的好处时&#xff0c;我说调用wait函数要一直检测子进程是否执行完…

Python3函数和代码复用

函数的定义 def 函数名([参数列表]):注释函数体注意事项 函数形参不需要声明类型&#xff0c;可以使用return语句在结束函数执行的同时返回任意类型的值&#xff0c;函数返回值类型与return语句返回表达式i的类型一致 即使该函数不需要接受任何参数&#xff0c;也必须保留一堆…