美文网首页
Linux 端口复用和I/O多路复用 2020-03-23(未经

Linux 端口复用和I/O多路复用 2020-03-23(未经

作者: 9_SooHyun | 来源:发表于2020-03-23 14:47 被阅读0次

端口复用

默认情况下,一个port只允许绑定一个socket,其他socket不允许绑定该port
例如,当出现time_wait时,服务端未释放TCP连接的socket占用着端口,其他客户端的请求想连接服务端时则无法连接

端口复用允许多个socket在同一ip:port上绑定和监听
例如,父进程监听P端口,多个client端过来连接,父进程fork多个子进程一一处理,父子进程们共用P端口。这样一来,即使出现大量time_wait,那些想要连接server的客户端依然可以正常连接,不会影响正常的业务

阻塞式IO和非阻塞式IO

阻塞式IO指进程/线程进行IO时,处于阻塞态,直到IO完成才继续往下运行
非阻塞式IO指进程/线程进行IO时,IO函数会立刻返回一个结果而不管IO是否完成,使得进程/进程继续往下运行

以老王买票为例——买到票为IO完成
阻塞式IO:到火车站发现没票,不吃饭不睡觉一直等了7天7夜等到别人退票
非阻塞式IO:到火车站发现没票,第二天再来问,没有,第三天再来,直到有票

I/O多路复用

先上定义:一个线程并发交替地顺序完成多个socket的I/O操作,就叫I/O多路复用。必须明确的是,“复用”指复用同一个线程

  • 历史背景:
    如果每个socket都单独由一个线程处理,那么处理socket的线程内的
int iresult = recv(s, buffer, 1024)

这个语句会等待对端的数据发送过来,要是对端没有发送数据,这个语句就会阻塞在这里,直到有数据可读。因此,阻塞式IO可能导致大量的线程都等待数据而阻塞,白白消耗资源
当然,我们也可以使用非阻塞IO,即读不到数据时返回一个错误标记,然后过段时间再来查有没有数据读。读不到-下次读这段时间内,线程也没事干,同样处于阻塞态

  • 改进:
    从上面可以看到,反正只要没读到数据,处理socket的线程都会被阻塞。那我们可以把多个socket都交给一个线程处理,这样即使这多个socket全部没数据读,也只阻塞一个线程而已。也就是I/O多路复用

  • 进程或线程调用select()/poll()/epoll()I/O多路复用
    select()/poll()/epoll()是3个系统调用function,进程或者线程可以通过调用它们实现I/O多路复用。调用它们之后进程或线程会从用户空间进入内核空间,直到它们返回

    • select()机制:基于轮询+数组。线程将要监控的系列socket的描述字(fd, file descriptor)加入数组,然后调用select()后线程会阻塞并等待select()这个系统调用返回。当数据到达时,fd状态改变,对应socket被激活,select函数返回(注意这里返回的是全部fd,具体哪个socket可读还要线程遍历一次才知道)。线程发起read请求,读取数据并继续执行
      Linux-io多路复用之select(图片源于网络)
      需要注意的是,线程向内核读数据时,必须使用非阻塞IO进行读取,也就是如果读不到数据的话这个线程不可以阻塞在那里。因为select返回有socket可读,但未必能读到数据——Under Linux, select() may report a socket file descriptor as "ready for reading", while nevertheless a subsequent read blocks. 【select()会返回可读,但可能在读的时候造成阻塞】This could for example happen when data has arrived but upon examination has wrong checksum and is discarded. 【比如数据来了但校验和经计算不对又被丢弃,变成无数据可读】There may be other circumstances in which a file descriptor is spuriously reported as ready. 【还有一些其他情况会造成通知可读但读时无数据而阻塞的情况】Thus it may be safer to use O_NONBLOCK on sockets that should not block.【因此必须配合使用非阻塞IO,即read不到数据时线程不阻塞,而是让read立刻返回一个错误,如EWOULDBLOCK】
    • poll()机制:原理与select()一致,但基于轮询+链表。因此,select()一次可监听的socket受到数组size的约束,而poll()则没有上限
    • epoll()机制:由于select()和poll()在返回时不能明确哪个socket可读,要遍历查询,而epoll()则进行了改进,为每个fd(file descriptor)注册回调,I/O准备好时,会执行回调,效率比select和poll高很多

暂时记录,如日后发现有理解不当之处再行修正

相关文章

网友评论

      本文标题:Linux 端口复用和I/O多路复用 2020-03-23(未经

      本文链接:https://www.haomeiwen.com/subject/trgiyhtx.html