ソケットを使って何かをテストしていますが、奇妙な状況に直面しました。
私はCで非常に単純なTCPサーバーを作成し、複数の接続試行が同時に許可されたときに何が起こるかを確認するためにaccept()後にサーバーをブロックしました。
以下は、サーバーコードから抜粋したものです。
//listen()
if( (listen(sock,5)) == -1) {
perror("listen");
exit(-1);
}
//accept()
if( (cli = accept(sock, (struct sockaddr *) &client, &len)) == 1 ){
perror("accept");
exit(-1);
}
printf("entrez un int : ");
scanf("%d",&toto);
サーバーがユーザーに整数を入力するように要求すると、Telnetを使用して複数のクライアントを接続しようとします。
Bastionが最初で、すべてがうまくいきます。
root@[...] :/home/[...]/workspace/sockets# netstat -antp | grep 10003
tcp 0 0 0.0.0.0:10003 0.0.0.0:* LISTEN 25832/toto
tcp 0 0 127.0.0.1:10003 127.0.0.1:51166 ESTABLISHED 25832/toto
tcp 0 0 127.0.0.1:51166 127.0.0.1:10003 ESTABLISHED 25845/telnet
ただし、最初の接続の後にはいくつかの接続があり、それを所有しているプロセスとそのPIDを見ることはできません。
root@[...] :/home/[...]/workspace/sockets# netstat -antp | grep 10003
tcp 0 0 0.0.0.0:10003 0.0.0.0:* LISTEN 25832/toto
tcp 0 0 127.0.0.1:10003 127.0.0.1:51166 ESTABLISHED 25832/toto
tcp 0 0 127.0.0.1:51166 127.0.0.1:10003 ESTABLISHED 25845/telnet
tcp 0 0 127.0.0.1:10003 127.0.0.1:51168 ESTABLISHED -
tcp 0 0 127.0.0.1:51168 127.0.0.1:10003 ESTABLISHED 25852/telnet
3番目:
root@[...] :/home/[...]/workspace/sockets# netstat -antp | grep 10003
tcp 0 0 0.0.0.0:10003 0.0.0.0:* LISTEN 25832/toto
tcp 0 0 127.0.0.1:10003 127.0.0.1:51166 ESTABLISHED 25832/toto
tcp 0 0 127.0.0.1:51166 127.0.0.1:10003 ESTABLISHED 25845/telnet
tcp 0 0 127.0.0.1:10003 127.0.0.1:51172 ESTABLISHED -
tcp 0 0 127.0.0.1:10003 127.0.0.1:51168 ESTABLISHED -
tcp 0 0 127.0.0.1:51168 127.0.0.1:10003 ESTABLISHED 25852/telnet
tcp 0 0 127.0.0.1:51172 127.0.0.1:10003 ESTABLISHED 25860/telnet
数日後、netstat -antpeをrootとして使用して再試行しましたが、これが私が得たものです。
root@[...] :/home/[...]/workspace/sockets# netstat -antpe | grep 10003
tcp 0 0 0.0.0.0:10003 0.0.0.0:* LISTEN 1000 327680 22399/toto
tcp 0 0 127.0.0.1:33286 127.0.0.1:10003 ESTABLISHED 1000 417202 22884/telnet
tcp 0 0 127.0.0.1:10003 127.0.0.1:33046 ESTABLISHED 0 0 -
tcp 0 0 127.0.0.1:10003 127.0.0.1:33286 ESTABLISHED 0 0 -
tcp 0 0 127.0.0.1:33044 127.0.0.1:10003 ESTABLISHED 1000 332810 22402/telnet
tcp 0 0 127.0.0.1:33046 127.0.0.1:10003 ESTABLISHED 1000 331200 22410/telnet
tcp 0 0 127.0.0.1:10003 127.0.0.1:33044 ESTABLISHED 1000 332801 22399/toto
プロセスや接続のinodeがゼロになるのはなぜですか?何が起こっているのかを説明できる人はいますか?
答え1
サーバーコードはaccept()
一度だけ呼び出されます。したがって、最初の接続試行のみが有効に承認され、残りのクライアント接続はカーネル空間の接続要求キューに残ります。再度呼び出されると、accept()
次のクライアント接続がキューから取得されます。
クライアント接続がカーネルスペースに残っている間は、参加するすべてのソケット記述子でオプションを有効にすると、複数のプロセスまたはスレッドが一意のアドレスとポートのペアの接続を合法的に許可できるため、どのプロセスもクライアント接続を所有しませんSO_REUSEPORT
。
SO_REUSEPORT
呼び出し前に次のコードを追加し、複数のサーバーを実行してbind()
このオプションを直接テストできます。カーネルがそれらの間で要求を配布することがわかります。
{
int enabled = -1;
if (setsockopt (sockd, SOL_SOCKET, SO_REUSEPORT,
(void*) &enabled, sizeof (enabled)) < 0) {
perror ("setsockopt");
}
}
参照ソースman 2 accept
:
これ受け入れ(sockfd)システムコールは、接続ベースのソケットタイプ(SOCK_STREAM、SOCK_SEQPACKET)で使用されます。リスニングソケットの保留中の接続キューから最初の接続要求を取得します。靴下、関連付けられた新しいソケットを作成し、ソケットを参照する新しいファイル記述子を返します。新しく作成されたソケットはリスニング状態ではありません。オリジナルソケット靴下この呼び出しの影響を受けません。
参照ソースman 7 socket
:
SO_REUSEPORT(Linux 3.9以降)
複数のAF_INETまたはAF_INET6ソケットを同じソケットアドレスにバインドできます。このオプションは、呼び出す前にすべてのソケット(最初のソケットを含む)に設定する必要があります。バインディング(2)ソケットに。ポートのハイジャックを回避するには、同じアドレスにバインドされているすべてのプロセスに同じ有効なUIDが必要です。このオプションはTCPおよびUDPソケットに使用できます。
TCPソケットの場合、このオプションを使用すると承諾(2)マルチスレッドサーバーの負荷分散は、スレッドごとに異なるリスナーソケットを使用して強化できます。これにより、単一のaccept(2)スレッドを使用して接続を分散したり、複数のスレッドを使用して競合したりするなど、従来の技術よりも負荷分散が向上します。承諾(2)同じアウトレットで。
UDPソケットの場合、このオプションを使用すると、複数のプロセスが同じソケットからデータグラムを受信するために競合する従来の技術よりも、複数のプロセス(またはスレッド)に入ってくるデータグラムをより効果的に配布できます。