IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 网络编程(三)IO多路复用及网络属性设置 -> 正文阅读

[系统运维]网络编程(三)IO多路复用及网络属性设置

Linux中的IO模型

  • 阻塞IO:最常用、最简单,但效率最低(read、write)

  • 非阻塞IO:防止进程阻塞在IO操作上,但必须使用轮询(浪费cpu资源)

  • ***IO多路复用:同时对多个IO进行操作,效率比阻塞高、浪费的cpu资源比非阻塞少

  • 信号驱动IO:一种异步通信

int fcntl(int fd, int cmd, ... /* arg */ );
{
    更改模式(如阻塞改为非阻塞)
    fd:文件描述符
    cmd:F_GETFD(空白)返回(作为函数结果)文件描述符;arg参数被忽略。
		F_SETFD (int)将文件描述符标志设置为该值指定的参数。
    arg:F_SETFD中使用
        
        F_GETFD模式的返回值可作参数,与阻塞,非阻塞等模式按位或,可更改模式
        
        ex:将标准输入改为非阻塞模式
    		{
        		int flag = fcntl(0, F_GETFL, 0);

			    flag |= O_NONBLOCK;
 
			    fcntl(0, F_SETFL, flag);
    		}
    
}
IO多路复用的思路
  • 先构造一张描述符的集合表

  • 使用一个函数,检测该表中哪一个或多个 文件描述符可进行IO操作

    该函数就立即返回 该文件描述符的标志

  • 根据该函数 返回的哪一个文件描述符,就可以进行IO操作

  • select、poll、epoll

  • select缺点,主要是:

    其一,每次调用select都需要将进程加入到所有监视socket的等待队列,每次唤醒都需要从每个队列中移除。这里涉及了两次遍历,而且每次都要将整个fds列表传递给内核,有一定的开销。正是因为遍历操作开销大,出于效率的考量,才会规定select的最大监视数量,默认只能监视1024个socket。

    其二,进程被唤醒后,程序并不知道哪些socket收到数据,还需要遍历一次。

    那么,有没有减少遍历的方法?有没有保存就绪socket的方法?这两个问题便是epoll技术要解决的。

int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);

{
    nfds : 为需要加入io描述符集的最大描述符+1
    readfds:读描述符集合表
    writefds:写描述符集合表
    exceptfds:其他描述符集合表 不需要时null
    timout:NULL时为阻塞,
        	0为非阻塞
        	》0表在当前time时间中阻塞,超过time后,立即返回
        
    返回值:
        timeout = null时	失败返回-1
  		timeout = time时,失败返回-1,超时返回0     
        
        值得注意的是每次调用select函数时,最好清理一下所对应的描述符文件。
}

void FD_CLR(int fd, fd_set *set);
将fd从set里清除
int  FD_ISSET(int fd, fd_set *set);
判断fd是否在set中(调用select函数后,set中会对所触发的fd进行标记),在返回真,不在返回0
void FD_SET(int fd, fd_set *set);
将fd加入到set中
void FD_ZERO(fd_set *set);
删除fd中的所有文件描述符

    同类型的描述符(读,写)装到同类型的集合表中.
    
    
fd:文件描述符 open打开的 
set:一个文件描述符集合

int ret = poll(pfd, 2, 5000);
{
    		// 参数1:要检测的文件描述符和事件的结构体数组 首地址
		// 参数2:要检测的文件描述符个数
		// 参数3:超时设置, 单位 毫秒
		// 成功:返回 非负值(可操作文件描述的元素的个数);超时:返回 0; 失败:返回-1
    	//向数组元素中装填 要检测的文件描述符和 事件
			pfd[0].fd = 0;				//文件描述符
			pfd[0].events = POLLIN;      //带检测的事件:数据可读
    
    			if( pfd[i].revents & pfd[i].events ){ //判断数组中哪个元素的 revents 被置位
				if( pfd[i].fd == 0){			  //判断数组中产生事件的元素中 文件描述符为 谁
 
                    struct polfd {
                        .fd,		//文件流
                        .events,	//感兴趣事件
                        .revents	//返回事件
                    }
}

TCP服务器端的并发

代码位置:$HOME/220304/05_network/day3/

poll/select/线程/进程

epoll

简单来说,就是epoll维护了一个红黑树和一个链表,需要监听的socket添加到红黑树上,哪个socket有事件过来,就把它加到链表上,然后发给用户通知。用户直接遍历这个链表,挨个处理即可。
而poll和select只返回有时间的fd的数量,并没有说是哪个fd,所以还需要挨个遍历所有fd去检查

https://zhuanlan.zhihu.com/p/64138532			epoll详解

int epoll_create(int size)//创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大
	失败返回 -1
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
{
	epfd : create的返回值
	op:		 EPOLL_CTL_ADD:往事件表中注册fd上的事件

     		 EPOLL_CTL_MOD:修改fd上的注册事件

    	 	 EPOLL_CTL_DEL:删除fd上的注册事件
    	 	 
    fd : 要操作的文件描述符
    
    event:指定事件
}
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
{

	epfd:creat返回值

	events:存放返回事件的数组首地址

	maxevents:最多返回个数
	
	timeout:指定-1的超时将导致epoll_wait()无限阻塞,而指定等于0的超时将导致epoll_wait()立即返回,即使没有可用的事件。
	
	返回值:超时返回0;
			错误返回-1
			成功返回可操作文件数量
}




struct epoll_event {
               uint32_t     events;    /* Epoll events */
               epoll_data_t data;      /* User data variable */
           };
        typedef union epoll_data {
               void    *ptr;
               int      fd;
               uint32_t u32;
               uint64_t u64;
           } epoll_data_t;

events事件
	EPOLLONESHOT
	对于注册了EPOLLONESHOT事件的文件描述符,操作系统最多出发其上注册的一个可读,可写或异常事件,且只能触发一次。
使用:
	注册了EPOLLONESHOT事件的socket一旦被某个线程处理完毕,该线程就应该立即重置这个socket上的EPOLLONESHOT事件,以确保这个socket下一次可读时,其EPOLLIN事件能被触发,进而让其他工作线程有机会继续处理这个sockt。
	
	EPOLLET
		使用EPOLLET标志的应用程序应该使用非阻塞的文件描述符,以避免阻塞的读或写饿死正在运行的任务
	其他看man手册
	
	https://blog.csdn.net/tjcwt2011/article/details/125169005

7 #include <stdio.h>
  8 #include <string.h>
  9 #include <stdlib.h>
 10 #include <strings.h>
 11 #include <unistd.h>
 12 #include <sys/epoll.h>
 13 #include <sys/types.h>
 14 #include <sys/stat.h>
 15 #include <fcntl.h>
 16 
 17 int main(int argc, char *argv[])
 18 {
 19     int epfd, nfds;
 20 
 21     int fd = open("/dev/input/mouse0", O_RDONLY);
 22     if(fd < 0)
 23     {
 24         perror("open");
 25         return -1;
 26     }
 27     struct epoll_event ev[2], events[5];// ev用于注册事件, 数组用于返回要处理的事件
 28 
 29     epfd = epoll_create(2);
 30 
 31     ev[0].data.fd = 0;
 32 
 33     ev[0].events = EPOLLIN ; //添加监听读状态同时设置ET模式
 34 
 35     ev[1].data.fd = fd;
 36 
 37     ev[1].events = EPOLLIN | EPOLLET;
 38 
 39     epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &ev[0]);  //注册epoll事件
 40     epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev[1]);
 41 
 42     for(;;)
 43     {
 44         nfds = epoll_wait(epfd, events, 5, -1); //阻塞等待epoll
 45         for(int i = 0; i < nfds; i++)
 46         {
 47             if(events[i].data.fd == 0)
 48                 printf("aaa\n");
 49             if(events[i].data.fd == fd)
 50                 printf("bbb\n");
 51 
 52         }
 53     }
 54 
 55 
 56 
 57     return 0;
 58 }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vwMDCa6N-1659336026436)(.\网络编程小笔记.assets\epoll.png)]

网络属性设置

int setsockopt(int sockfd, int level, int optname, const void * optval, socklent optlen)
{
    sockfd:套接字
    level: SOL_SOCKET :通用套接字选项
        	IPPROTO_IP :IP选项
            IPPROTO_TCP:TCP选项
    optname:如下图
    optval|optlen: 根据数据类型决定,如:类型为int,那么就设置一个int on 为optval,on为1表示打开,
					optlen就是sizeof(on),类型为sturct timeval,就是设置超时时间       
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uzwgSg02-1659336026437)(.\网络编程小笔记.assets\网络属性.png)]

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-08-06 11:16:52  更:2022-08-06 11:19:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 0:45:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码