2013-06-01 28 views
5

この質問は、Network port open, but no process attached?netstat shows a listening port with no pid but lsof does notに似ています。しかし、彼らの答えは私のものを解決することはできません。プログラムが接続されていない接続が常に5つあるのはなぜですか?

が、私はポート8588.

[[email protected] lcms]# netstat -lnp | grep 8588 
tcp  0  0 0.0.0.0:8588    0.0.0.0:*     LISTEN   6971/lps 

あなたが見ることができるようにTCP接続を待ちlpsと呼ばれるサーバーアプリケーションを持って、何もリスニングソケットと間違っありませんが、私は(いくつかの千テストクライアントを接続したときに書かれました2000年、3000年、4000年のいずれにせよ)、サーバーにログイン要求を接続して送信しても、応答を受け取ることのできないクライアントが5つ(ランダムでもあります)あります。 3000クライアントを例に取る。

[[email protected] lcms]# lsof -i:8588 | grep ES | wc -l 
2995 

5つの接続はここにいる:

[[email protected] 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は、それらが接続されていることを示して

[[email protected] lcms]# netstat -nap | grep 8588 | grep ES | wc -l 
3000 

そして、これがlsofコマンド出力です:これはnetstatコマンドは与えるものですポート8588のサーバーに接続しますが、プログラムは接続されていません。 2番目の列(RECV-Q)は、クライアントが要求を送信するにつれて増加し続けます。

上記のリンクでは、NFSマウントとRPCについて説明しています。 RPCのためとして、私はコマンドrcpinfo -pを使用し、その結果は、nfssta出力がError: No Client Stats (/proc/net/rpc/nfs: No such file or directory).

質問言いポート8588.そして、NFSマウントとは何の関係もありません:どのようにこれが起こることができますか?常に5人で、同じ5人のクライアントではない。他のクライアントも同じサーバーのIPとポートに接続されており、すべてがサーバーによって適切に処理されるため、ポートの競合とは思われません。

注:クライアントのリクエストを受け入れるには、epollのLinuxを使用しています。私は私のプログラムにデバッグコードを書いて、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年6月8日: のCentOS 6.4にシステムをアップグレードした後、同様の問題が発生します。最後に私はepollに戻って、this pageが、ノンブロッキングであることを聴く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を使用している場合は、常にreadまたはacceptからEAGAINが出てくることを覚えておいてください。テストプログラムで私を証明してくれてありがとうMatthewにもう一度感謝します。

+0

ご使用の環境でIP 192.168.0.241について特別なことはありますか? – Nils

+0

もう1つは@Nilsに追加されましたが、私はそれがIP 192.168.0.241の問題だとは思いません。我々はいくつかのテスト仮想マシンを持っており、それらは5つのホストから来ることができます。 – leowang

+0

ちょっと待ってください。このサーバーはあなたが書いているプログラムを 'lps'していますか? –

答えて

1

私は、次のパラメータを使用して、問題を複製しようとしました:

  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 

私は、あまりにも成功して、リモートマシン上のサーバとのテストを試してみた私は3000

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

を取得し、クライアントに接続されているIP接続の数を確認します。

私は同じことを試みることをお勧めします。

さらに、iptablesをいくつかの接続が奇妙に追跡する場合に備えて、iptablesを完全にオフにしてみてください。 時には/procのiptablesオプションも役に立ちます。したがって、sysctl -w net.netfilter.nf_conntrack_tcp_be_liberal=1を試してください。

編集:私はあなたの側で見る出力を生成する別のテストを行った。あなたの問題は、サーバー側の接続を先制的にシャットダウンすることです。

私は、次のあなたがやって見ているものと同様の結果を再現することができます

  • 私のサーバーにいくつかのデータを読んだ後、shutdown(fd, SHUT_RD)を呼び出します。
  • サーバー上でsend(fd, buf, sizeof(buf))を実行します。

これを実行すると、次のような動作が発生します。

  • クライアントでは、netstat/ssでESTABLISHEDを使用して3000の接続を開きます。
  • lsof出力では、2880(シャットダウンの仕組みの性質)の接続が確立されます。
  • 残りの接続lsof -i:8558 | grep -v ESはCLOSE_WAITにあります。

これは、ハーフシャットダウン接続でのみ発生します。

これは私があなたのクライアントまたはサーバープログラムのバグだと思われます。いずれかのサーバーにオブジェクトを送信するサーバーに何かを送信しているか、何らかの理由でサーバーが無効に接続を終了しています。

「異常な」接続の状態(close_waitなど)を確認する必要があります。

私はこの段階でも、プログラミング上の問題であり、実際にはserverfaultに属するものではないと考えています。クライアント/サーバのソースの関連部分を見ることなく、誰でも障害の原因を追跡することはできません。私はこれがオペレーティングシステムが接続を処理する方法とはまったく関係がないと確信しています。

+0

テストプログラムを書く時間を節約してくれてありがとう。私のマシンでのテスト結果はあなたのものと同じです。私はサーバープログラムをブロックしてリッスンするfdに戻し、3000の接続も受け入れることができます。しかし、来るべきデータ処理を元のルーチンに戻すと、受け入れられない接続が失われたものが返されます。また、iptablesをオフにして、 'sysctl'のパラメータを変更することをお勧めしました。まだ動かない。 – leowang

+0

処理の面では、I/O、メモリまたはCPUがロードされていますか? –

+0

元の回答に更新を加えました。私はこれもおそらくここに属さないので、これをstackoverflowに移行することに投票しました。 –

関連する問題