当前位置:网站首页>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);
}
}
边栏推荐
猜你喜欢
随机推荐
【HQL】(一)json字符串处理json_tuple和get_json_object
极光推送 能否缓存 消息
漫谈Map Reduce 参数优化
Let small program development into ` tailwind jit ` era
pta a.1003 的收获
浏览器中的 preview 和 response 的值不一致
[CSRF, SSRF, XXE, PHP deserialization, Burpsuite]
陆运信息系统——班列项目总结(一)
寄存器常见指令
中国水煤浆行业“十四五”规划与运营模式分析报告2022~2028年
中国认证认可服务行业“十四五”发展规划及经营模式分析报告2022~2028年
速来围观,17个运维实用技巧
令人愉快的 Nuxt3 教程 (二): 快速轻松地搭建博客
中国生物反应器行业市场投资分析及前景预测报告2022~2028年
Oracle 密码策略详解
Hook初探索
玩转Markdown(2) —— 抽象语法树的提取与操纵
jsp通过form表单提交数据到servlet报404
当我们在看Etherscan的时候,到底在看什么?
中国石油行业并购重组趋势与投资战略规划建议报告2022~2028年