当前位置:网站首页>IO 复用
IO 复用
2022-08-03 05:23:00 【纸鸢805】
1. 端口复用设置
作用 : 解决address already is use 报错 的问题 ( 端口被占用, 可能没被释放 )
使用 : 放在socket 的 bind 前面;
int opt_val = 1;
//端口复用设置 socketfd1 网络连接标识符
setsockopt(socketfd1, SOL_SOCKET, SO_REUSEADDR, (const void*)&opt_val, sizeof(opt_val));
2. socket IO复用
复用一般有三种技术
1. select
不记录发出 I/O 者的描述符, 因此只能无差别轮询所有流,找出能读出数据,或者写入数据的流,采用的是数组存储;
2. poll
poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态, 但是它没有最大连接数的限制,原因是它是基于链表来存储的。
3. epoll ( 下面介绍的函数就是epoll技术 )
应用场景
select的timeout参数精度为1nm,比poll和epoll的1ms精度更高,因此select适合实时性要求比较高的场景。select的可移植性非常的好。
poll没有最大描述符数量的限制,如果平台支持并且对实时性要求不高,应该使用poll而不是select
只需要运行在linux平台下,有大量的描述符需要同时轮询,并且这些连接最好时长连接。在监听少量的描述符的适合,体现不出epoll的优势。
2.1 关键函数
2.1.1 Epoll 的创建, 返回的是个数
int cpoll_size = epoll_create(int size);
2.1.2 Epoll 的操作 (增 删 改)
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
参数 :
epfd :
epoll 结构体对象
op :
EPOLL_CTL_ADD 注册新的fd到epfd中
EPOLL_CTL_MOD 修改已注册的fd的监听事件
EPOLL_CTL_DEL 从epfd中删除一个fd
fd :
要监听的描述符
event :
表示要监听的事件
2.1.3 epoll_wait 函数等待事件的就绪,成功时返回就绪的事件数目
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
例如:
epollwritefd = epoll_wait(epollfd, epolleventArr, 10, -1); //函数等待事件的就绪参数:
调用失败时返回 -1,等待超时返回 0。
epfd 是epoll句柄
events 表示从内核得到的就绪事件集合 maxevents 告诉内核events的大小
timeout 表示等待的超时事件
2.2 socket IO复用 的使用 :
1. 定义struct epoll_event 结构体的对象, 与struct epoll_event 结构体数组。
struct epoll_event epollevent;
struct epoll_event epolleventArr[10];
int epollfd = 0; //epollevent 的数量
int epollwritefd = 0; //epolleventArr[10] 的数量2. 设置 struct epoll_event 结构体对象监听的文件描述符 , 与监听事件( EPOLLIN )
epollevent.data.fd = socketfd1; //设置连接监听
epollevent.events = EPOLLIN; //设置监听的事件为有数据传输进来3. 创建 epoll
epollfd = epoll_create(10);
if (epollfd == -1)
{
perror(" epoll_create error ! ");
}4. epoll 添加
//添加 socketfd1 进 epollevent 中
epoll_ctl(epollfd, EPOLL_CTL_ADD, socketfd1, &epollevent);5 . 函数等待事件就绪
epollwritefd = epoll_wait(epollfd, epolleventArr, 10, -1); //函数等待事件的就绪
if ( epollwritefd <= 0 )
{
perror(" epoll_wait error ! ");
}6. 分为等待 客户端连接 与 客户端数据传递
循环 for (int i = 0; i < epollwritefd ; i++) 完成以下两种操作
// 客户端连接
if (epolleventArr[i].data.fd == socketfd1)
{
cout << epollfd << "服务器端正在等待客户端访问:" << endl;
//等待客户端访问, 阻塞函数
kehuduanfd = accept(socketfd1, NULL, NULL);
if (kehuduanfd == -1)
{
perror(" accept error ! ");
}
else
{
cout << "客户端 " << kehuduanfd << "访问服务器成功!" << endl;
epollevent.data.fd = kehuduanfd;
epollevent.events = EPOLLIN;
epoll_ctl(epollfd, EPOLL_CTL_ADD, kehuduanfd, &epollevent);
}
}// 客户端传输数据到服务器
if(epolleventArr[i].events & EPOLLIN)
{
cout << " 有数据传输不是客户端登录 " << endl;
bzero(&stu1, sizeof(stu1));
res = read(epolleventArr[i].data.fd, &stu1, sizeof(STU));
if ( res > 0 )
{
cout << " res = " << res << endl;
cout << "stu1.stuId = " << stu1.stuId << endl;
cout << "stu1.stuName = " << stu1.stuName << endl;
cout << "stu1.miaoshu = " << stu1.miaoshu << endl;
bzero(&stu1, sizeof(STU));
}
else if ( res <= 0 ) // 客户端下线 (读到的数据为 0 就是客户端有问题应该是下线了)
{
cout << "客户端 " << kehuduanfd << "关闭" << endl;
epollevent.data.fd = kehuduanfd;
epollevent.events = EPOLLIN;
epoll_ctl(epollfd, EPOLL_CTL_DEL, epolleventArr[i].data.fd, &epollevent);
close(epolleventArr[i].data.fd);
}
}
边栏推荐
猜你喜欢
随机推荐
Go (二) 函数部分1 -- 函数定义,传参,返回值,作用域,函数类型,defer语句,匿名函数和闭包,panic
令人愉快的 Nuxt3 教程 (二): 快速轻松地搭建博客
docker mysql 容器中执行mysql脚本文件并解决乱码
Qlik Sense 判空详解(IsNull)
滚动条 scrollbar 和scrollbar-thumb 样式
Kotlin 中的泛型介绍
Apache2-XXE漏洞渗透
Qlik Sense 临时处理表数据详解(Resident)
动态调整web主题(2) 萃取篇
Flask,1-2
Invalid signature file digest for Manifest main attributes解决方法
Greetings(状压DP,枚举子集转移)
时间盲注脚本
pta a.1003 的收获
Ansible installation and deployment detailed process, basic operation of configuration inventory
寄存器常见指令
3559. 围圈报数
Oracle null 有哪些注意事项【面试题】
用户登录验证程序的实现
动漫:海贼王女









