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

这个问题类似于networking端口打开,但没有附加过程? 而netstat显示一个没有pid的监听端口,但是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 

正如你所看到的,监听套接字没有什么问题,但是当我将数千个testing客户端(由另一个同事写的)连接到服务器时,无论是2000,3000还是4000.总是有5个客户端随机)连接并发送login请求到服务器,但不能收到任何回应。 以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 mount, nfssta输出表示Error: No Client Stats (/proc/net/rpc/nfs: No such file or directory).

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

注意:我正在使用Linux epoll来接受客户端请求。 我也在我的程序中编写debugging代码,并logging每个套接字(以及客户端的信息) accept回报,但无法find5个连接。 这是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 ,发现这个页面说,设置听fd是非阻塞,并accept直到EAGAINEWOULDBLOCK错误返回。 是的,它的工作原理。 没有更多的连接正在等待。 但为什么呢? Unixnetworking编程第一卷

 accept is called by a TCP server to return the next completed connection from the front of the completed connection queue. If the completed connection queue is empty, the process is put to sleep (assuming the default of a blocking socket). 

所以如果队列中还有一些已经完成的连接,为什么这个进程会进入hibernate状态呢?

更新 2013-7-1:在添加侦听套接字时使用EPOLLET ,所以如果不接受EAGAIN ,我不能接受。 我刚刚意识到这个问题。 我的错。 请记住:如果使用EPOLLET ,即使正在监听套接字,也要始终readaccept直到EAGAIN出来。 再次感谢马修给我一个testing程序。

我已经尝试使用以下参数重复您的问题:

  1. 服务器使用epoll来管理连接。
  2. 我做了3000个连接。
  3. 连接被阻塞。
  4. 服务器基本上被简化为仅处理连接,并且执行非常复杂的工作。

我不能重复这个问题。 这是我的服务器源代码。

 #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(); } } 

这里是客户端:

 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) 

在本地机器上运行时,我得到了使用端口8558(1个监听,3000个客户端插座和3000个服务器端插座)的6001个插座。

 $ ss -ant | grep 8558 | wc -l 6001 

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

 # lsof -p$(pgrep python) | grep IPv4 | wc -l 3000 

我也尝试了与远程机器上的服务器测试成功。

我建议你试着去做。

另外尝试完全关闭iptables,以防万一它的一些连接跟踪怪癖。 有时/proc的iptables选项也可以帮助你。 所以试试sysctl -w net.netfilter.nf_conntrack_tcp_be_liberal=1

编辑:我做了另一个测试,产生你在你身边看到的输出。 你的问题是你正在关闭服务器端的连接。

我可以复制类似于您所看到的执行以下操作的结果:

  • 在读取一些数据到我的服务器后,调用shutdown(fd, SHUT_RD)
  • send(fd, buf, sizeof(buf))在服务器上send(fd, buf, sizeof(buf))

这样做后,可以看到以下行为。

  • 在客户端,我得到了3000个连接在netstat / ss中用ESTABLISHED打开。
  • 在lsof输出中,我得到了2880(我是如何关机的)性质。
  • 其余的连接lsof -i:8558 | grep -v ES lsof -i:8558 | grep -v ES在CLOSE_WAIT中。

这只发生在半关机连接上。

因此,我怀疑这是您的客户端或服务器程序中的一个错误。 您要么发送一些东西到服务器所反对的服务器上,要么服务器因某种原因无效地关闭连接。

你需要确认什么状态的“异常”连接(如close_wait或其他)。

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