如何正确的收发数据(基于IO多路复用)
前置
- 非IO多路复用,这种情况一般都是一个连接一个进程/线程,对应的IO模型是IO阻塞、IO非组模型,是在一个进程/线程里面完成数据的收发,整个流程是利用同步IO完成的同步编程(同步的进行收发即可)。
- 基于IO多路复用,需要配合IO复用函数来判断socket的可读可写事件。
如何正确的收数据(对于服务器)
- 与客户端建立连接得到clientfd,将clientfd绑定到对应的IO复用函数上,监听clientfd的读事件,读事件触发,就利用recv读取数据, 数据可能一次收完, 或者多次收取.
- 对于epoll的水平模式, 可以每次只收取一部分, 对于边缘模式, 必须通过while循环全部收完, 通过recv返回-1 ,errno是
EWOULDBLOCK
.
如何正确的发数据
- 对于发数据, 除了epoll的边缘模式外, 通常不会去注册可写事件, 因为大多数情况下, socket都是可写的, 水平模式会导致IO复用函数一直触发.
- 一般都是先send直接发送, 当如果发送过程中 返回-1, 且errno是
EWOULDBLOCK
表示TCP窗口太小数据无法写入, 这个时候还有数据没法出去, 就需要注册可写事件, 当数据发完了, 需要取消可写事件.
epoll 的边缘和水平模式的数据收发
- 水平模式:
- 收数据: 一般是先注册读事件, 读事件触发, 进行收数据, 只需要注册一次, 只要缓冲区有数据就会一直触发, 且可以进行任意的收取数据, 当连接关闭的时候, 需要取消挂载.
- 发数据: 一般是先发数据, 如果由于TCP窗口太小导致数据没法完, 需要注册可写事件, 如果数据一直没发完, 也不需要重复注册可写事件, 等待触发就可以了, 当数据发完了, 需要取消注册的可写事件, 一般不是网络出问题, socket一直都是可写的, 为了避免当没数据要发的时候一直触发水平模型的情况, 就需要取消可写事件.
- 边缘模式:
- 收数据: 注册可读事件, 当缓存区有数据需要while循环直到收完, 不然缓存区残留数据,边缘模式下次不会触发.
- 发数据: 可以一开始就注册可写事件, 然后去发数据, TCP窗口太小, 导致数据没发完, 数据能发的时候, 注册的可写事件会触发让你去发数据, 所以只需要注册一次可写事件, 不要取消可写事件的注册. 但是如果正常情况下, socket是一直可写的, 那数据发完, 还想监听可写事件, 需要重新注册可写事件, 不然不会触发, 也就是说, 边缘模式的可写, 只有socket从不可写到可写才会触发.