在 centos 7 上同步确认后的插座鳍

socket fin after syn ack on centos 7

我用 epoll 写了一个 tcp 服务器,它在 Ubuntu 上运行正常,但在 CentOS7 上偶尔会发生奇怪的事情。

客户端a尝试连接到服务器b,连接已建立, 客户端端口为59298,服务器端口为8802,服务器端socketfd为16.

[同义词]

[同步、确认]

[确认]

同时服务器读取 return 值为零的事件,具有相同的 sockfd,即 16,与之前的连接建立相同,告诉 a 和 b 之间的连接已关闭。服务器发送一个 [rst,ack] 包到不同端口的客户端,即 59191。为什么会这样?是centos内核的bug吗?

我的代码与下面的代码非常相似。

       #define MAX_EVENTS 10
       struct epoll_event ev, events[MAX_EVENTS];
       int listen_sock, conn_sock, nfds, epollfd;

       /* Set up listening socket, 'listen_sock' (socket(),
          bind(), listen()) */

       epollfd = epoll_create(10);
       if (epollfd == -1) {
           perror("epoll_create");
           exit(EXIT_FAILURE);
       }

       ev.events = EPOLLIN;
       ev.data.fd = listen_sock;
       if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
           perror("epoll_ctl: listen_sock");
           exit(EXIT_FAILURE);
       }

       for (;;) {
           nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
           if (nfds == -1) {
               perror("epoll_pwait");
               exit(EXIT_FAILURE);
           }

           for (n = 0; n < nfds; ++n) {
               if (events[n].data.fd == listen_sock) {
                   conn_sock = accept(listen_sock,
                                   (struct sockaddr *) &local, &addrlen);
                   if (conn_sock == -1) {
                       perror("accept");
                       exit(EXIT_FAILURE);
                   }
                   setnonblocking(conn_sock);
                   ev.events = EPOLLIN | EPOLLET;
                   ev.data.fd = conn_sock;
                   if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
                               &ev) == -1) {
                       perror("epoll_ctl: conn_sock");
                       exit(EXIT_FAILURE);
                   }
               } else {
                   do_use_fd(events[n].data.fd);
               }
           }
       }

这是我的 tcpdump 结果。

看了man epoll才知道原因。它是由于不合适的代码而发生的。

 epoll_ctl(epollfd_, EPOLL_CTL_DEL, sockfd, &ev)

在github上似乎很少有关于epoll的正确使用示例。