サーバーは、どのクライアントポートに送信するかをどのように見つけますか?


26

私が理解しているように、これはクライアントが接続要求を行ったときに起こることです:

  1. サーバーは特定のポート番号にバインドされます。ポート番号は常にリスニングプロセスにバインドされます。サーバーのみが着信接続をリッスンしているため、クライアント側でバインドする必要はありません。
  2. サーバーはそのポート番号でlisteninigを継続します。
  3. クライアントはconnect()リクエストを送信します。
  4. サーバーはを使用してリクエストを受け入れますaccept()。サーバはクライアントの要求を受け入れるとすぐに、カーネルはさらに、サーバーのためのポート番号をランダムに割り当てとしてsend()およびreceive()サーバー上の同じポート番号を聞くだけでなく、送信するために使用することはできない、と以前のポートがまだあることから、新しい接続をリッスンする

以上のことを考えると、サーバーはクライアントが受信しているポートをどのようにして見つけるのでしょうか?クライアントが送信元ポートと宛先ポートを使用してTCPセグメントを送信することを知っているので、サーバーはそのセグメントの送信元ポートを宛先ポートとして使用しますが、サーバーはそのポートを見つけるためにどの関数を呼び出しますか?それはaccept()


回答:


33

パケット内のTCP(またはUDPなど)ヘッダーの一部です。そのため、サーバーはクライアントがそれを伝えるためにそれを見つけます。これは、クライアントのIPアドレス(IPヘッダーの一部)を見つける方法に似ています。

たとえば、すべてのTCPパケットにはIPヘッダーが含まれています(少なくともソースIP、宛先IP、およびプロトコル[TCP]を含む)。次に、TCPヘッダーがあります(送信元ポートと宛先ポート、およびその他)。

カーネルは、リモートIP 10.11.12.13(IPヘッダー内)およびリモートポート12345(TCPヘッダー内)のSYNパケット(TCP接続の開始)を受信すると、リモートIPとポートを認識します。 。SYN | ACKを送り返します。ACKが返されると、listen呼び出しはその接続用に設定された新しいソケットを返します。

TCPソケットは、4つの値(リモートIP、ローカルIP、リモートポート、ローカルポート)によって一意に識別されます。少なくとも1つが異なる限り、複数の接続/ソケットを使用できます。

通常、ローカルポートとローカルIPは、サーバープロセスへのすべての接続で同じです(たとえば、sshdへのすべての接続はlocal-ip:22にあります)。1台のリモートマシンが複数の接続を行う場合、それぞれが異なるリモートポートを使用します。したがって、リモートポートを除くすべてが同じになりますが、それは問題ありません。4つのうち1つだけを異ならせる必要があります。

たとえば、wirehsarkを使用してパケットを表示すると、すべてのデータにラベルが付けられます。強調表示されているソースポートは次のとおりです(デコードされたパケットで強調表示されていることに注意してください。下部の16進ダンプも同様です)。

TCP SYNパケットを示すWireshark


>説明に感謝します。したがって、uはaccept()後に取得された新しいサーバーソケット記述子(つまりタプル)がクライアントポートとクライアントアドレスの詳細を持ち、その新しいソケット記述子サーバーを使用してデータを送受信することを意味しましたクライアントから。新しいソケットファイル記述子は、カーネル、サーバーIP、クライアントIP、およびクライアントポートによって割り当てられた新しいサーバーポート番号を持つことになります。
スビスレシュ

@SubiSureshはい、タプルはカーネル内に保存され、そのファイル記述子に関連付けられています。
デロバート

> derobertに感謝します。したがって、新しいサーバーソケット記述子には、サーバーがaccept()から取得するクライアントポートとクライアントアドレスを持つことになります。
スビスレシュ

@SubiSureshはい、それは正しいです。アプリケーションの観点からは、通常は気にしません(ロギングを除く)。カーネルは、あなたwrite(など)が正しい場所に行くことを確認します。
デロバート

>あなたの助けに感謝し、私はポイントを得たと思います。;-)
スビスレシュ

2

「接続要求(connect()通常はクライアントプログラムのシステムコール)により、3ウェイハンドシェイクが発生します。3ウェイハンドシェイクの最初のパケット(クライアントからサーバーへ)にはSYNフラグが設定され、クライアントプログラムのTCPポート番号が含まれますカーネルがそれに割り当てます。

これは、Nmap vs Natural SYNパケットに関する記事で見ることができます。Nmap SYNパケットのデコードには、「source.60058> dest.22」というフレーズがあります。「正当なSYNパケット」のデコードには、「source.35970> dest.80」というフレーズが含まれています。2つのSYNパケットは、パケットがそれぞれTCPポート60058およびポート35970からのものであることをリモートカーネルに伝えます。


>しかし、裏で起こっているブルース・end.But私のサーバーは、実際に詳細をフェッチしているか、ポート番号は、クライアント・サーバ・プログラムで、通常becuaseのように、私は、クライアントポートとクライアントのアドレスを取得するために任意の関数を見たことがありません
サビ・スレッシュ

システムコールgetpeername()を使用すると、開いているすべてのソケットで実行できます。accept()サーバー・コードがクライアントに通信するソケットファイルディスクリプタを取得するために使用しなければならないことをシステムコールは、将来のクライアントのIPアドレスとTCPポート番号が含まれています(私のmanページで「のsockaddr」)のパラメータを持っています。
ブルースエディガー

elloborateを気にしないでくださいすべての入力から、accept()はクライアントの詳細で満たされた構造sockaddr_inを持ち、accept()の後に返される新しいサーバーソケット記述子はクライアントポートとアドレスを自動的に持つことを理解しました。だからこそ、send(新しいサーバーソケット記述子)を使用して送信できるのです。私が理解していることが正しいことを確認するためだけです。
スビスレシュ

@SubiSuresh-あなたは真実を書いたと思う。
ブルースエディガー

1

TCPソケットは、ストリーム指向のソケットです。2つのソケット記述子(ユーザーとピアが所有)は確実に接続されます。したがって、クライアントのポートを心配する必要はありません-ソケット記述子を記述するだけです!

また、(たぶんログを記録するために)本当に知りたい場合は、getsockname(2)をお気軽に。


0

接続はタプル(ソースIP、ソースポート、宛先IP、宛先ポート)によって定義されます。答えは逆になります。


@vondrand vonを理解した点ですが、サーバーはどのポートからクライアントのポート番号を知るようになりますか?港 ?
スビスレシュ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.