加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > Linux > 正文

linux – 为什么总是连接5个没有程序的连接?

发布时间:2020-12-14 01:43:03 所属栏目:Linux 来源:网络整理
导读:这个问题类似于 Network port open,but no process attached?和 netstat shows a listening port with no pid but lsof does not.但是它们的答案无法解决我的问题,因为它太奇怪了. 我有一个名为lps的服务器应用程序,它等待端口8588上的tcp连接. [root@centos
这个问题类似于 Network port open,but no process attached?和 netstat shows a listening port with no pid but lsof does not.但是它们的答案无法解决我的问题,因为它太奇怪了.

我有一个名为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 mount和RPC.至于RPC,我使用了命令rcpinfo -p,结果与端口8588无关.而NFS mount,nfssta输出显示错误:没有客户端统计信息(/ proc / net / rpc / nfs:没有这样的文件或目录) .

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

注意:我正在使用Linux epoll来接受客户端请求.我还在我的程序中编写调试代码并记录接受返回但无法找到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,发现this page说set listen fd是非阻塞的并接受,直到EAGAIN或EWOULDBLOCK错误返回.是的,它有效.没有更多的连接待定.但那是为什么呢? Unix网络编程第1卷说

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).

因此,如果队列中仍有一些已完成的连接,为什么进程会进入休眠状态?

更新2013-7-1:
我在添加监听套接字时使用EPOLLET,所以如果不遇到EAGAIN,我就不能接受所有接受.我刚刚意识到这个问题.我的错.请记住:如果使用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,NULL };

static int create_srv_socket(const char *port) {
  int fd = -1;
  int rc;
  struct addrinfo *ai = NULL,hints;

  memset(&hints,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,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,sizeof(buf));

  if ((rc = recv(fd,buf,sizeof(buf),0)) <= 0) {
    rc ? warn("Cannot read from socket") : 1;
    return false;
  }

  if (send(fd,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).
>在服务器上发送(fd,sizeof(buf)).

执行此操作后,可以看到以下行为.

>在客户端,我使用ESTABLISHED在netstat / ss中打开3000个连接.
>在lsof输出中,我得到2880(我正在关机的性质)建立的连接.
>其余的连接lsof -i:8558 | grep -v ES在CLOSE_WAIT中.

这只发生在半关闭连接上.

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

您需要确认“异常”连接的状态(如close_wait或其他).

在这个阶段,我也认为这是一个编程问题,而不是属于serverfault的东西.在没有看到客户端/服务器的源的相关部分的情况下,任何人都无法追踪故障原因.尽管我非常有信心这与操作系统处理连接的方式无关.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读