Linux上的TCP监听fd的accept/select/poll/epoll惊群问题

本文探讨了Linux系统中TCP监听时的惊群问题,特别是在2.6.32及更高内核版本的情况。通过实验,作者发现对于3.10内核,accept、select和epoll都已经解决了惊群问题。实验代码展示了如何在多进程中使用accept、select和epoll,并观察它们的行为。结论指出,从2.6.32内核开始,Linux的accept已经避免了惊群现象,但在select和epoll中情况有所不同。
摘要由CSDN通过智能技术生成

同一个TCP端口(地址相同)是不能被多次绑定、监听的。因此,多线程程序无法并发地accept连接。而多进程可以并发accept新连接,办法就是先创建、绑定好端口,完成listen调用,然后fork出子进程,子进程继承父进程的文件描述符,然后子进程、父进程都可以accept。

       很多石器时代的C/C++程序员认为,如果有一个新连接建立完成,此时阻塞在accept系统调用上的进程都会被唤醒,但是只有一个进程accept成功(这种现象叫做惊群,哈哈哈)。

事实果真如此吗???这个问题的答案取决于内核(Unix/类Unix/Linux,以及具体哪个内核版本,都可能导致答案不同,鄙人只探讨Linux平台,没有BSD操作系统的历史包袱,也没有AIX/Solaris等商业操作系统的环境和必要)。我不喜欢不去思考内核行为的程序员,因为他们太过自负,而且不懂得与时俱进地更新自己的知识。

        操作系统内核是干什么的?这很明显是取决于内核的一个特性呀。

        操作系统内核版本迭代,做了什么?他们以为仅仅是修复下bug,增加下版本号吗?

测试环境:

VirtualBox在Windows工作站上虚拟4核心,4GB内存机器,安装CentOS-6.10,来提供2.6.32内核环境(这里很可能对测试结果造成了影响,即同一个进程被唤醒,但是我条件限制暂时无法确认)

 

阿里云上本人有一台4核心8G内存机器,来提供3.10内核测试环境

4核心 3.10.0-693.el7.x86_64 #1 SMP Tue Aug 22 21:09:27 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

不过,有一点很明确,对于3.10内核来说,accept/select/epoll都解决了惊群问题

代码如下(子进程没有优雅地退出,新连接也没有优雅地关闭,要手动杀死子进程,原谅小哥哥这里的偷懒):

#include <iostream>
#include <unistd.h>
#include <string>
#include <cstring>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>

using   namespace std;


int     set_opts(int fd)
{
        const int enable = 1;
        int ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
        if(ret != 0)
        {
                cout << "setsockopt.addr.ret=" << ret << ",fd=" << fd << endl;
                return  ret;
        }

        ret = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable));
        if(ret != 0)
        {
                cout << "setsockopt.port.ret=" << ret << ",fd=" << fd << endl;
             

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值