Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 为什么总是有5个连接没有附加程序?_Linux_Networking_Netstat_Lsof - Fatal编程技术网

Linux 为什么总是有5个连接没有附加程序?

Linux 为什么总是有5个连接没有附加程序?,linux,networking,netstat,lsof,Linux,Networking,Netstat,Lsof,这个问题类似于和。但这些问题的答案无法解决我的问题,因为这太奇怪了 我有一个名为lps的服务器应用程序,它在端口8588上等待tcp连接 [root@centos63 lcms]# netstat -lnp | grep 8588 tcp 0 0 0.0.0.0:8588 0.0.0.0:* LISTEN 6971/lps 正如您所看到的,侦听套接字没有任何问题,但是当我将数千个测

这个问题类似于和。但这些问题的答案无法解决我的问题,因为这太奇怪了

我有一个名为
lps
的服务器应用程序,它在端口8588上等待tcp连接

[root@centos63 lcms]# netstat -lnp | grep 8588   
tcp        0      0 0.0.0.0:8588                0.0.0.0:*                   LISTEN          6971/lps
正如您所看到的,侦听套接字没有任何问题,但是当我将数千个测试客户机(由另一位同事编写)连接到服务器时,无论是2000、3000还是4000。始终有5个客户端(也是随机的)连接并向服务器发送登录请求,但无法接收任何响应。以3000个客户为例。这是
netstat
命令给出的结果:

[root@centos63 lcms]# netstat -nap | grep 8588 | grep ES | wc -l
3000
这是
lsof
命令输出:

[root@centos63 lcms]# lsof -i:8588 | grep ES | wc -l
2995
这里有5个连接:

[root@centos63 lcms]# netstat -nap | grep 8588 | grep -v 'lps'                   
tcp    92660      0 192.168.0.235:8588          192.168.0.241:52658         ESTABLISHED -                   
tcp    92660      0 192.168.0.235:8588          192.168.0.241:52692         ESTABLISHED -                   
tcp    92660      0 192.168.0.235:8588          192.168.0.241:52719         ESTABLISHED -                   
tcp    92660      0 192.168.0.235:8588          192.168.0.241:52721         ESTABLISHED -                   
tcp    92660      0 192.168.0.235:8588          192.168.0.241:52705         ESTABLISHED -                   
上面的5显示它们已连接到端口8588上的服务器,但未连接任何程序。第二列(即
RECV-Q
)随着客户端发送请求而不断增加

上面的链接介绍了NFS装载和RPC。至于RPC,我使用了命令
rcpinfo-p
,结果与端口8588无关。和NFS装载,
nfssta
输出显示
错误:没有客户端统计信息(/proc/net/rpc/NFS:没有这样的文件或目录)。

问:这是怎么发生的?始终为5,也不是来自相同的5个客户。我不认为这是端口冲突,因为其他客户端也连接到相同的服务器IP和端口,并且它们都由服务器正确处理

注意:我使用Linux
epoll
来接受客户端请求。我还在程序中编写调试代码,并记录
accept
返回但找不到5个连接的每个套接字(以及客户端信息)。这是
uname-a
输出:

Linux centos63 2.6.32-279.el6.x86_64 #1 SMP Fri Jun 22 12:19:21 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
谢谢你的帮助!我真的很困惑


更新2013-06-08: 将系统升级到CentOS 6.4后,也会出现同样的问题。最后,我返回到
epoll
,发现set listen fd是非阻塞的,
accept
,直到
EAGAIN
ewoldblock
返回错误。是的,它起作用了。没有更多的连接挂起。但为什么呢?Unix网络编程第1卷说

那么,如果队列中仍有一些已完成的连接,为什么要将进程置于睡眠状态

更新2013-7-1:
我在添加侦听套接字时使用了
EPOLLET
,因此,如果在遇到
EAGAIN
之前不保留accept,我将无法接受所有内容。我刚刚意识到这个问题。是我的错。请记住:如果使用
EPOLLET
,请始终
读取
接受
,直到
EAGAIN
出现,即使它正在侦听套接字。再次感谢Matthew用测试程序证明了我的能力。

我尝试使用以下参数复制您的问题:

  • 服务器使用epoll来管理连接
  • 我有3000个连接
  • 连接被阻塞
  • 服务器基本上“简化”为只处理连接,只执行很少的复杂工作
  • 我不能重复这个问题。这是我的服务器源代码

    #include <stddef.h>
    #include <stdint.h>
    #include <stdbool.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    #include <errno.h>
    #include <netdb.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/epoll.h>
    
    #include <err.h>
    #include <sysexits.h>
    #include <string.h>
    #include <unistd.h>
    
    struct {
      int numfds;
      int numevents;
      struct epoll_event *events;
    } connections = { 0, 0, NULL };
    
    static int create_srv_socket(const char *port) {
      int fd = -1;
      int rc;
      struct addrinfo *ai = NULL, hints;
    
      memset(&hints, 0, sizeof(hints));
      hints.ai_flags = AI_PASSIVE;
    
      if ((rc = getaddrinfo(NULL, port, &hints, &ai)) != 0)
        errx(EX_UNAVAILABLE, "Cannot create socket: %s", gai_strerror(rc));
    
      if ((fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0)
        err(EX_OSERR, "Cannot create socket");
    
      if (bind(fd, ai->ai_addr, ai->ai_addrlen) < 0)
        err(EX_OSERR, "Cannot bind to socket");
    
      rc = 1;
      if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &rc, sizeof(rc)) < 0)
        err(EX_OSERR, "Cannot setup socket options");
    
      if (listen(fd, 25) < 0)
        err(EX_OSERR, "Cannot setup listen length on socket");
    
      return fd;
    }
    
    static int create_epoll(void) {
      int fd;
      if ((fd = epoll_create1(0)) < 0)
        err(EX_OSERR, "Cannot create epoll");
      return fd;
    }
    
    static bool epoll_join(int epollfd, int fd, int events) { 
      struct epoll_event ev;
      ev.events = events;
      ev.data.fd = fd;
    
      if ((connections.numfds+1) >= connections.numevents) {
        connections.numevents+=1024;
        connections.events = realloc(connections.events, 
          sizeof(connections.events)*connections.numevents);
        if (!connections.events)
          err(EX_OSERR, "Cannot allocate memory for events list");
      }
    
      if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) < 0) {
        warn("Cannot add socket to epoll set");
        return false;
      }
    
      connections.numfds++;
      return true;
    }
    
    static void epoll_leave(int epollfd, int fd) {
      if (epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL) < 0)
        err(EX_OSERR, "Could not remove entry from epoll set");
    
      connections.numfds--;
    }
    
    
    static void cleanup_old_events(void) {
      if ((connections.numevents - 1024) > connections.numfds) {
        connections.numevents -= 1024;
        connections.events = realloc(connections.events,
          sizeof(connections.events)*connections.numevents);
      }
    }
    
    
    static void disconnect(int fd) {
      shutdown(fd, SHUT_RDWR);
      close(fd);
      return;
    }
    
    static bool read_and_reply(int fd) {
      char buf[128];
      int rc;
      memset(buf, 0, sizeof(buf));
    
      if ((rc = recv(fd, buf, sizeof(buf), 0)) <= 0) {
        rc ? warn("Cannot read from socket") : 1;
        return false;
      }
    
      if (send(fd, buf, rc, MSG_NOSIGNAL) < 0) {
        warn("Cannot send to socket");
        return false;
      }
    
      return true;
    }
    
    int main()
    {
      int srv = create_srv_socket("8558");
      int ep = create_epoll();
      int rc = -1;
      struct epoll_event *ev = NULL;
    
      if (!epoll_join(ep, srv, EPOLLIN)) 
        err(EX_OSERR, "Server cannot join epollfd");
    
      while (1) {
        int i, cli;
    
        rc = epoll_wait(ep, connections.events, connections.numfds, -1);
        if (rc < 0 && errno == EINTR)
          continue;
        else if (rc < 0)
          err(EX_OSERR, "Cannot properly perform epoll wait");
    
        for (i=0; i < rc; i++) {
          ev = &connections.events[i];
    
          if (ev->data.fd != srv) {
    
            if (ev->events & EPOLLIN) {
              if (!read_and_reply(ev->data.fd)) {
                epoll_leave(ep, ev->data.fd);
                disconnect(ev->data.fd);
              }
            } 
    
            if (ev->events & EPOLLERR || ev->events & EPOLLHUP) {
              if (ev->events & EPOLLERR)
                warn("Error in in fd: %d", ev->data.fd);
              else
                warn("Closing disconnected fd: %d", ev->data.fd);
    
              epoll_leave(ep, ev->data.fd);
              disconnect(ev->data.fd);
            }
    
          }
          else {
    
            if (ev->events & EPOLLIN) {
              if ((cli = accept(srv, NULL, 0)) < 0) {
                warn("Could not add socket");
                continue;
              }
    
              epoll_join(ep, cli, EPOLLIN);
            }
    
            if (ev->events & EPOLLERR || ev->events & EPOLLHUP)
              err(EX_OSERR, "Server FD has failed", ev->data.fd);
    
          }
        }
    
        cleanup_old_events();
      }
    
    }
    
    当在本地机器上运行时,我使用端口8558获得6001个套接字(1个侦听,3000个客户端套接字和3000个服务器端套接字)

    当检查客户端上连接的IP连接数时,我得到3000个

    # lsof -p$(pgrep python) | grep IPv4 | wc -l
    3000
    
    我还尝试了在远程机器上使用服务器进行测试,并取得了成功

    我建议你也这样做

    此外,尝试完全关闭iptables,以防出现连接跟踪问题。 有时
    /proc
    中的iptables选项也会有所帮助。因此,请尝试使用sysctl-w net.netfilter.nf\u conntrack\u tcp\u be\u liberal=1

    Edit:我做了另一个测试,生成了您看到的输出。您的问题是您正在先发制人地关闭服务器端的连接

    我可以通过以下操作复制与您看到的类似的结果:

    • 将一些数据读入我的服务器后,调用
      shutdown(fd,shuth\u RD)
    • 在服务器上执行
      发送(fd、buf、sizeof(buf))
    执行此操作后,会看到以下行为

    • 在客户机上,我在netstat/ss中打开了3000个已建立的连接
    • 在lsof输出中,我建立了2880(我如何关机的性质)连接
    • 其余的连接
      lsof-i:8558 | grep-v ES
      处于关闭等待状态
    这只发生在半关机连接上

    因此,我怀疑这是您的客户端或服务器程序中的一个错误。您正在向服务器对象所指向的服务器发送某些内容,或者服务器由于某种原因正在无效地关闭连接

    您需要确认“异常”连接处于什么状态(如close_wait或其他)


    在这个阶段,我也认为这是一个编程问题,而不是真正属于服务器故障的问题。如果看不到客户机/服务器源的相关部分,任何人都不可能找到故障原因。尽管我很有信心,但这与操作系统处理连接的方式无关。

    在您的环境中,IP 192.168.0.241有什么特别之处吗?在@Nils中再添加一个,我认为这不是IP 192.168.0.241的问题。我们有几个测试虚拟机,这5个可以来自不同的主机。请稍候。这台服务器是您正在编写的程序吗?@MichaelHampton是的。感谢您抽出时间编写测试程序。在我的机器上的测试结果和你的一样。我修改我的服务器程序回到阻止监听fd,也可以接受3000个连接。但回到原来的常规数据处理,这些服务水平
    from socket import *
    import time
    scks = list()
    
    for i in range(0, 3000):
      s = socket(AF_INET, SOCK_STREAM)
      s.connect(("localhost", 8558))
      scks.append(s)
    
    time.sleep(600)
    
    $ ss -ant | grep 8558 | wc -l
    6001
    
    # lsof -p$(pgrep python) | grep IPv4 | wc -l
    3000