多路IO转接服务器

多路IO转接服务器

学习目标:

掌握端口复用函数
了解半关闭及shutdown函数
掌握select实现多路IO转接
了解poll函数
掌握epoll实现多路IO转接


端口复用:

int  setsockopt(int sockfd,int level,int optname,const void *optval,socklen_t optlen);

参数
scokfd:标识一个套接口的描述字。
level:选项定义层次;支持SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP和IPPROTO_IPV6。
optname:需设置的选项。
optval:指针,指向存放选项待设置的新值的缓冲区。
optlen:optval缓冲区的长度。

常用方法设置端口复用

int opt = 1; //设置端口复用
setsockopt(lfd,SOL_SOCKET,SO_REUSEADDR,(void *)&opt,sizeof(opt));

半关闭:

通信双方中只有一方关闭

close(cfd);
shutdown(int fd,int how);

参数
scokfd:标识一个套接口的描述字。
how:SHUT_RD、SHUT_WR、SHUT_RDWR。

shutdown在关闭多个文件描述符应用的文件时,采用全关闭方法。close,只关闭一个。


select函数:

select函数: 该函数用于监视文件描述符的变化情况——读写或是异常。

int select(int maxfd + 1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout);

参数
maxfd + 1:最大文件描述符加1。
readset:用于检查可读性。
writeset:用于检查可写性。
exceptset:用于检查带外数据。
timeout:一个指向timeval结构的指针,用于决定select等待I/O的最长时间。
timeout:

  • > 0:设置监听超时时长。
  • NULL 阻塞监听。
  • 0:非阻塞监听,轮询。

返回值
>0:就绪描述字的正数目。
-1:出错。
0:超时。

select优缺点:

  • 优点:跨平台
  • 缺点:
    • 监听上限受文件描述符限制。最大1024
    • 检测满足条件的fd,自己添加业务逻辑提高小。提高了编码难度。

poll函数:

poll函数: 把当前的文件指针挂到等待队列。

int poll(struct pollfd *fds,nfds_t nfds,int timeout);

参数
fds:监听的文件描述符【数组】。
nfds:事件有效监听数组的个数。
timeout:

  • > 0:超时时长,单位毫秒。
  • -1:阻塞等待
  • 0:不阻塞

返回值
满足对应监听事件的文件描述符总个数。

poll优缺点:

  • 优点:
    • 自带数组结构,可以将监听事件集合和返回事件集合分离。
    • 扩展监听上限,超时1024限制。
  • 缺点:
    • 不能跨平台
    • 无法直接定位满足监听事件的文件描述符,编码难度较大。

epoll函数:

poll函数: 为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。

int epoll_create(int size);//创建一个epoll的句柄。
int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event);//epoll事件注册函数,先注册要监听的事件类型。
int epoll_wait(int epfd,struct epoll_event *events,int maxevents,int timeout);//等待事件的产生

参数
size:创建的红黑树的监听节点数量(仅供内核参考)。
epfd:epoll_create函数的返回值。
op:对该监听红黑树所作的操作。

  • EPOLL_CTL_ADD:添加fd到监听红黑树。
  • EPOLL_CTL_MOD:修改fd在监听红黑树上的监听事件。
  • EPOLL_CTL_DEL:将一个fd从监听红黑树上摘下(取消监听)。

fd:待监听的fd。
event:本质struct epoll_event 结构体地址。
events:传出参数,满足监听条件的fd结构体。
maxevents:数组元素的总个数。1024
timeout:

  • > 0:超时时长,单位毫秒。
  • -1:阻塞等待
  • 0:不阻塞

返回值
epoll_create:函数
成功:指向新创建的红黑树的根节点fd。
失败:-1 设置errno。
epoll_ctl:函数
成功:0。
失败:-1 设置errno。
epoll_wait:函数
> 0:满足监听的总个数,可用作循环上限。
-1:失败 设置errno。
0:没有fd满足监听事件。

struct epoll_event{
__uint32_t events;
epoll_adta_t data;
};
//events可以是一下即个宏的集合
//- EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
 //- EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
  //- EPOLLERR:表示对应的文件描述符发生错误;
//- EPOLLHUP:表示对应的文件描述符被挂断;
//- EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
 //- EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里。
 /***********************************/
 //data:联合体
typedef union epoll_data{
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
}epoll_data_t;

epoll事件模型:

  • ET模式: 边沿触发,缓冲区剩余未读尽的数据不会导致epoll_wait返回,新的事件满足才会触发。(EPOLLET)
  • LT模式: 水平触发(默认采用模式),缓冲区剩余未读尽的数据会导致epoll_wait返回。

结论: epoll的ET模式,高效模式,但只支持非阻塞模式(忙轮询)。
使用方法

struct epoll_event event;
event.events = EPOLLIN | EPOLLET;
epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&event);
int flag = fcntl(cfd,F_GETFL);
flag |= O_NONBLOCK;
fcntl(cfd,F_SETFL,flag);

补充:

read函数返回值:
返回值
> 0:实际读到的字节数。
= 0:socket中,表示对端关闭。
-1:
- 如果errno == EINTR (被异常中断,需要重启)。
- 如果errno == EAGIN 或 EWOULDBLOCK(以非阻塞方式读数据,但是没有数据,需要再次读)。
- 如果errno == ECONNRESET(说明连接被重置,需要close(),移除监听队列。)。

突破1024文件描述符限制:

cat /proc/sys/fs/file-max  #当前计算机所能打开的最大文件个数,受硬件影响
ulimit -a #当前用户下的进程,默认打开文件描述符个数。缺省为1024

修改文件

sudo vi /etc/security/limits.conf
#写入
#  softnofile 65536 设置默认值,可以直接借助命令修改【注销用户、使其生效】
#  hard nofile 100000 命令修改上限。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值