当前位置: 首页 > ops >正文

关于linux网络编程——4

总结:

[服务器编程 -- IO多路复用]
1.单循环服务器
socket
bind
listen

while (1)
{
connfd = accept
//通信 

2.并发服务器 --- 进程或线程 
socket
bind
listen

while (1)
{
//任务1 接收客户端的连接 
connfd = accept
fork
pthread_create
//任务2 通信 
}  
同时可以处理多个客户端 
3.提高并发的程度 
IO多路复用 
//多路 
//复用 

IO模型
//阻塞IO   ---  简单 低效 
//非阻塞IO  ---  轮询 + CPU(负担中)
//信号驱动IO ---  发信号通知一下  
//SIGIO
//处理数量有限 
//IO多路复用 
//
10进程或线程 
10进程或线程 --- 监控多路IO  
-------------------------------
select 


多路IO复用的服务器: //实现并发 --- 可以同时处理多个客户端

listenfd = socket
bind
listen
//connfd = accept
//1.准备表
fd_set readfds;
FD_ZERO(&readfds);
//2.添加要监控的文件描述符 
FD_SET(listenfd,&reafds);
//3.准备参数 
maxfds = listenfd + 1;
fd_set backfds; 
while (1)
{   
backfds = readfds;
int ret = select(maxfds,&backfds,NULL,NULL,NULL);
if (ret > 0)
{
int i = 0;
for (i = 0; i < maxfds;++i)
{
if (FD_ISSET(i,&backfds))
{
if (i == listenfd) //连接 
{
connfd = accept();
//connfd 要被添加到 监控表
FD_SET(connfd,&readfds);
if (connfd + 1 > maxfds)
maxfds = connfd + 1;
}else //负责与客户端通信 
{
//    i = ?//fd 此时就绪 
printf("buf = %s\n",buf);
if (strncmp(buf,"quit",4) == 0)
{
FD_CLR(i,&readfds); //清除对应的客户端的fd
close(i);    
}
}
}
}
}
}

//优化
int i = maxfds;
for (i = maxfds-1; i >= 0; --i)
{
if (FD_ISSET(i,&readfds))
{
maxfds = i + 1;
}
}

不足:
缺点
1. 最大监听数受限:`FD_SETSIZE` 默认 1024(Linux)
2. 每次调用需重置 fd_set:内核会修改集合,必须每次重新 `FD_SET`
3. 用户态与内核态拷贝开销大
4. 返回后仍需遍历所有 fd 才能知道哪个就绪
5. 效率随 fd 数量增长下降明显

一、pol函数

#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
功能:  对文件描述符监控 
参数:@fds     struct pollfd {int   fd;         /* file descriptor */short events;     /* requested events */short revents;    /* returned events */};events 事件:POLLIN    读 POLLOUT   写 POLLERR   错误 @nfds  表示要监控的文件描述符的数量 @timeout 时间值 -1 //阻塞 时间值 单位 是 ms (毫秒)0  //非阻塞 n(>0) //阻塞 n ms(毫秒)
返回值:成功 表示 就绪的数量 0 超时情况下表示 没有就绪实际失败 -1  

二、使用思路

使用://1.准备监控表 struct pollfd fds[10]; //监控表示 10个fd //2.添加要监控的文件描述符   //点对点聊天 //两路io -- stdin / sockfd int nfds = 0;fds[0].fd = 0;fds[0].events = POLLIN;nfds++;fds[1].fd = sockfd;fds[1].events = POLLIN;nfds++;//3.准备参数 while (1){int ret = poll(fds,nfds,-1);if (ret > 0){int i = 0;for (i = 0; i < nfds; ++i){if(fds[i].revents&POLL_IN){if (fds[i].fd == 0){fgetssend}else //sockfd { recvprintf			 }}}}}   

三、poll实现的并发服务器

//poll实现的并发服务器:
多路IO复用的服务器: //实现并发 --- 可以同时处理多个客户端
listenfd = socketbindlisten
//1.准备表struct pollfd fds[10];
//2.添加要监控的文件描述符 int nfds = 0;fds[0].fd = listenfd;fds[0].events = POLL_IN;nfds++;while (1){   int ret = poll(fds,nfds,-1);if (ret > 0){int i = 0;for (i = 0; i < nfds;++i){if (fds[i].revents&POLL_IN)){if (fds[i].fd == listenfd) //连接 {connfd = accept();//connfd 要被添加到 监控表fds[nfds].fd = connfd;fds[nfds].events = POLL_IN;nfds++;		  }else //负责与客户端通信 {//	i = ?//fd 此时就绪 recv(fds[i].fd,buf,sizeof(buf),0);printf("buf = %s\n",buf);if (strncmp(buf,"quit",4) == 0){fds[i].fd = -1;  //-1 不是有效的文件描述符 close(fds[i].fd);	}}}}}
}

四 改进与不足:
相比 select 的改进
1. 无 1024 限制:只要系统允许打开足够多 fd
2. 无需重置集合:`events` 和 `revents` 分离
3. 更清晰的事件机制
4. 效率更高:仅遍历传入的数组,不遍历整个 fd 范围

仍存在的问题
- 每次调用仍需将整个 `fds[]` 拷贝到内核
- 返回后仍需遍历全部元素查找就绪 fd
- 时间复杂度仍是 O(n),连接数多时性能下降

五、epoll

5.1函数

#include <sys/epoll.h>
int epoll_create(int size);
功能:创建一个epoll对象 
参数:@size 忽略,但是必须大于0 
返回值:成功 epoll对象的fd失败 -1 &&errno #include <sys/epoll.h>int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:控制 epoll对象
参数:@epfd   epoll对象的fd@op    EPOLL_CTL_ADD   //添加EPOLL_CTL_MOD   //修改 EPOLL_CTL_DEL   //删除 @fd     //要关心的文件描述符   @event 	typedef union epoll_data {void        *ptr;int          fd;uint32_t     u32;uint64_t     u64;} epoll_data_t;struct epoll_event {uint32_t     events;      /* Epoll events */epoll_data_t data;        /* User data variable */};struct epoll_event  ev;
ev.events = EPOLLIN;  
ev.data.fd = 0; //stdin EPOLLIN  //读 EPOLLOUT //写 EPOLLERR //出错EPOLLET  //边沿触发___      ___|    ||    |-----中断:-- //电平(水平)触发  ---  有数据 ,它就会一直通知  //边沿触发	      ---  没数据,有数据 ---触发  ----只会通知一次返回值:成功 0失败 -1 &&errnoint epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
功能:监控对应的文件描述符 ,看是否有就绪
参数:@epfd  --epoll对象@events     ---保存就绪结果的 一个数组的首地址 @maxevents  ---数组的大小 struct epoll_event ret_ev[2];@timeout    ---超时的时间 时间单位,还是ms (毫秒数)
返回值:成功  就绪的数量 失败  -1 && errno被设置 

5.2使用流程:

1.epoll_create //创建了一个epoll对象 ---- 监控的表 int epfd = epoll_create(2);
2.添加文件描述符 
//一个是 标准输入 0
//一个是 sockfd 
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = 0; //标准输入 
epoll_ctl(epfd,EPOLL_CTL_ADD, 0, &ev);int add_fd(int fd, int epfd)
{struct epoll_event ev;ev.events = EPOLLIN;ev.data.fd = fd; //标准输入 if ( epoll_ctl(epfd,EPOLL_CTL_ADD, fd, &ev)){perror("epoll_ctl add fail");return -1;}	return 0;
}int del_fd(int fd, int epfd) //删除 
{//struct epoll_event ev;//ev.events = EPOLLIN;//ev.data.fd = fd; //标准输入 if ( epoll_ctl(epfd,EPOLL_CTL_DEL, fd, NULL)){perror("epoll_ctl add fail");return -1;}	return 0;
}add_fd(0,epfd);//标准输入
add_fd(clifd,epfd);//socket3.监控文件描述符 
while (1)
{struct epoll_event ret_ev[10];int ret = epoll_wait(epfd, ret_ev,3, -1);if (ret > 0){int i = 0;for (i = 0; i < ret; ++i){if (ret_ev[i].data.fd == 0){}else  //socket{}}}}

http://www.xdnf.cn/news/19730.html

相关文章:

  • 醋酸铕:点亮现代生活的“隐形之光“
  • HTML元素周期表
  • 【C++】C++入门—(中)
  • ASP.NET Web Forms 实战:用 RadioButton 打造“性别/称谓选择”表单的最佳实践
  • 【数据结构】1绪论
  • 【Qt中信号槽连接connect有接收者和无接收者的区别】
  • 执行一条select语句期间发生了什么?
  • 常用符号 Emoji 对照表——Unicode UTF-8
  • CSS Sass Less 样式.xxx讲解
  • SpringMVC的请求接收与结果响应
  • 华为HCIE数通含金量所剩无几?考试难度加大?
  • 数据库选择有讲究?SQLite、PostgreSQL还是MySQL?
  • 电脑接入企业中的网线,为啥网卡上面显示AD域名
  • MongoDB 聚合查询超时:索引优化与分片策略的踩坑记录
  • 国产CAD皇冠CAD(CrownCAD)建模教程:汽车驱动桥
  • 二、Scala流程控制:分支与循环
  • 波浪模型SWAN学习(2)——波浪浅化模拟(Shoaling on sloping beach)
  • RoPE频率缩放机制:解密大语言模型上下文扩展的核心算法
  • linux之IO存储子系统全流程分析
  • 差分隐私在运营指标:ABP 的 DP 计数器与噪声预算
  • 使用PyTorch构建全连接神经网络实现MNIST手写数字分类
  • 【面试题】 如何处理中文分词?
  • LeetCode 2486.追加字符以获得子序列
  • ubuntu的2T新硬盘分区、格式化并挂载
  • Python进阶第三方库之Numpy
  • GO : cannot find module
  • 【音视频】 RGB 格式详解
  • 1.Linux:命令提示符,history和常用快捷键
  • 程序员之电工基础-初尝线扫相机
  • 百度发布Comate AI IDE,我要把Cursor卸载了!