网络IO杂谈

网络IO杂谈,第1张

网络IO杂谈

有关网络IO的内容可能都涉及一点,但是只涉及一点,所以……杂谈。
网络IO的核心,是处理好四个问题:连接建立、连接断开、数据到达、数据可发送。

阻塞和非阻塞IO

阻塞和非阻塞IO的区别,就是他们在对应缓冲区不可读或不可写(缓冲区满)的时候,是否直接返回。一句话说,就是数据未准备好,是否阻塞等待。这里的阻塞,是阻塞在网络线程上。非阻塞的设置如下

fcntl(fd, F_SETFL, O_NONBLOCK);

这里还要注意一点,非阻塞是指数据准备阶段,在数据准备好之后,用户空间到系统空间之间的拷贝都是阻塞的。
##网络模型
简单介绍两种网络模型。

阻塞IO+多线程

一个线程处理一个连接。此时不会设置非阻塞IO,因为如果非阻塞,线程就会一直检测IO,浪费CPU。
这种模型,优点是响应及时,毕竟“专门服务”,但是缺点也很明显,线程的利用率不高,要是一直没有数据,那就是一直阻塞。

IO多路复用

之前讨论过这个模型,这里再介绍一下epoll相关的问题,IO主要作用于数据准备阶段,但是epoll还可以检测其他相关的状态,如连接的状态、keepalive等。另外,对于EPOLLHUP这个状态,指fd的读通道和写通道都关闭。再提示一下,epoll_wait()中的timeout可与定时器相结合。

reactor模型

这里需要注意,对于IO多路复用,读写IO阻塞与非阻塞都可以,但是reactor中一定要使用非阻塞IO。

单reactor模型

redis使用的模型,网络与业务处理都在同一线程中。

单reactor+任务队列+线程池

reactor处理网络事件,将业务处理扔给线程池处理,实现网络事件处理与业务流程想分离。

多reactor模型

多线程
典型代表是memcached。它是一个主线程处理accept,其余线程处理读写事件。线程间用pipe通信。这里简单介绍一下多线程pipe通信的模型。因为pipe是单向通信,只能一端读另一端写,所以在memcached中,主线程在pipe中写,其他线程负责读(使用select)。
多进程
典型代表是nginx。master进程产生多个worker进程,每个worker进程负责读写、监听,每个worker进程都有一套reactor。

补充

最后再补充零星几点。

半关闭状态

半关闭状态CLOSE_WAIT是客户端关闭了写通道,shutdown(SHUT_WR)发送⼀个 FIN 包,服务器接受到了客户端的FIN包,但仍要继续向客户端发送数据的状态。skynet支持半关闭状态,而redis、memcached、nginx不支持,是直接close(fd)。
具体细节
shutdown(SHUT_WR)发送⼀个FIN包,并且标记该socket为SEND_SHUTDOWN;
shutdown(SHUT_RD)不发送任何包,但是标记该socket为RCV_SHUTDOWN;
发送端发送FIN包,并且标记该socket为SEND_SHUTDOWN;
收到FIN包标记该 socket 为RCV_SHUTDOWN。
另外对于epoll⽽⾔,如果⼀个socket同时标记为SEND_SHUTDOWN和RCV_SHUTDOWN;那么epoll会返回EPOLLHUP;
如果⼀个socket被标记为RCV_SHUTDOWN;epoll会返回EPOLLRDHUP。
这里再提示一点,close(fd)只是将系统中该fd的引用计数减一,并没有真正关闭。内核在检测到fd没有引用之后,才会释放相应的连接数据。

几个errno

EINTR:fd被中断打断。系统调用时,不会发生线程切换,但是中断的优先级比系统调用高,如果发生了中断,线程就可能发生切换,即被打断了,此时errno置为EINTR。于EWOULDBLOCK一样,需下次重试。注意epoll中做法有区别,LT的话下次重新检测event即可,不需要额外 *** 作,ET就必须自己重试。
ETIMEDOUT:TCP探活包超时。之前有介绍,TCP有keepalive机制,在指定时间内以指定间隔发送指定数量的SYN包,都没收到对端的ACK包。这些数量、间隔、时间,都可以在/etc/sysctl.conf中设置

net.ipv4.tcp_keepalive_time=7200  #单位是秒
net.ipv4.tcp_keepalive_intvl=75  #单位是秒
net.ipv4.tcp_keepalive_probes=9

上面是对系统全局设置,也可以对单个连接设置,可以使⽤三个属性设置:TCP_KEEPCNT、TCP_KEEPIDLE、TCP_KEEPINTVL。

setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val));
setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val));
setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val));

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5720375.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-18

发表评论

登录后才能评论

评论列表(0条)

保存