网络IO之IO管理


记录在零声学院所学的点点滴滴,方便后续查看。欢迎提出问题!相互探讨

什么是网络IO

客户端连接服务器所产生的fd

为什么要使用select,epoll,poll

当多个客户端连接在服务器时,如何判断哪个有数据。

传统做法:

1、开多线程
缺点: fd 做的不多

2、while循环receive所有io
缺点: 当网络io成千上万时,大量的时候是没有数据的。

因此,专门用个组件(类似于select等多路复用),判别io里面有没有数据。

IO三种状态

  • 是否可读
  • 是否可写
  • 是否出错

IO五种网络模型

阻塞IO (blocking IO)

非阻塞IO(non-blocking IO)

多路复用IO (IO multiplexing)

select

其实select就是利用位图进行操作
主要代码

// fd_set: 位图。存储所有fd的状态,0和1
fd_set rfds, rest;

// 将所有的fd置0
FD_ZERO(&rfds);

// 将位图上sockfd对应的状态置1
FD_SET(sockfd, &rfds);

int maxfd = sockfd + 1;

// 不断检测io里面有没有数据
while (1) {
 rset = rfds;
 // param1: 最大的fd数+1;   param2: 是否可读; param3: 是否可写; param4: 是否出错; param5: 时间戳 
 // param5: 为 NULL:如果关注fd没有一个值,则一直阻塞。 有值:在该值范围内筛选
 // nready:满足需求的个数。如下为筛选可读的io个数。
 int nready = select(maxfd, &rset, NULL, NULL, NULL);
 if (nready < 0) continue;
 
 // 判断sockfd,是否在rset里面
if(FD_ISSET(sockfd, &rset)) {
	 struct sockaddr_in clientaddr;
	 int clientfd = accept(sockfd, (struct aockaddr*) &client_addr, &client_len);
	 if (clientfd < 0) continue;
	
	 FD_SET(clientfd,  &rfds);
	 if(clientfd > maxfd) maxfd = clientfd;

	 printf("sockfd: %d, max_fd:%d, clientfd: %d\n", sockfd, max_fd, clientfd);

	 if(--nready == 0) continue;
 }
for (i = sockfd +1; i <= max_fd; i++) {
	if (FD_ISSET(i, &rset)) {
	 char buffer[BUFFER_LENGTH] = {0};
	 int ret = recv(i, buffer, BUFFER_LENGTH,0);
	 if (ret < 0) {
	    // recv里面没有数据
	 	if (errno == EAGAIN || errno == EWOULDBLOCK) {
	 		printf("read all data");
	 	}
	 	FD_CLR (i, &rfds);
	 	close(i);
	 } else if(ret == 0) {
	 	printf ("disconnect %d\n", i);
	 	FD_CLR(i, &rfds);
	 	close(i);
	 	break;
	}else {
		printf("Recv: %s, %d Betys\n", buffer, ret);
	}
	if (-- nready == 0) break;
 }
}

总结:

  • 用一个位图存储fd
  • select函数 选出 满足需求(可读、可写) 的fd位图
  • 对位图上的客户端进行遍历,得到数据。依次循环。
epoll

概述:
类似于蜂巢快递柜, 快递员往快递柜存快递, 小区的人在快递柜拿快递

重要函数
epoll_create(int size) : 为小区请快递员。创建跟节点

size :只有大于0和等于0的区别。传一和十万是一样的。最初实现的时候是有意义的,为就绪队列的长度

epoll_ctl(): 信息的修改。 红黑树添加修改节点
epoll_wait(): 快递员多长时间跑一下小区。多长时间抓就绪队列里的节点

实质
由红黑树和队列组成。红黑树包含所有的fd, 队列里面包含的是有数据的fd, 也叫做就绪队列。
红黑树和就绪队列共享节点。当有数据时, fd加入就绪队列。

ET:边沿触发。无数据到有数据则触发

LT:水平触发。recvbuff里面有数据就一直触发

大块数据(发送数据大于recvbuff)建议用LT, 小块数据建议ET。
listen 的时候 建议用ET。避免丢失少许客户端的连接。用LT的话,accpect可能会丢。 

总结:

  • epoll_create()创建跟节点
  • epoll_ctrl() epoll_fd 与 socketfd相连接。
  • epoll_wait()得出有数据的就绪队列。
  • 对就绪队列里面的fd进行循环获取数据
poll

仅仅是把select函数里的param2,param3,param4合在了一起。

异步IO (Asynchronous I/O)

信号驱动IO (signal driven I/O)

信号量与信号

信号量: PV操作

信号: 给每个进程通知的信号

举例说明
kill -9 进程名字: 向进程发送信号

使用场景
当进程初始化连接数据库,不可控条件退出时,可以用信号函数捕获或清空网络

其他
信号处理函数具体是在内核态用户态切换时调用的

相关函数

// 信号与进程绑定
sigaction(SIGIO,  &sigio_action, NULL);

// 给fd设置相关的参数,比如阻塞和非阻塞
fcntl(sockfd, F_SETOWN, getpis());

其他

异步怎么理解(形容两者间的关系)

检测IO是否有数据与读写数据这两步操作不在一个流程里面

非阻塞和非阻塞(设置IO的状态)

非阻塞:有没有数据都返回
阻塞:有数据就读取,没有数据则不读

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值