私が理解したところ、クライアントが接続要求をすると、次のことが起こります。
- サーバーは特定のポート番号にバインドされます。ポート番号は常に受信プロセスに関連付けられています。サーバーだけが着信接続を受信しているため、クライアント側でバインドする必要はありません。
- サーバーは引き続きこのポート番号をリッスンします。
connect()
クライアントが要求を送信します。- サーバーは承認要求を使用します
accept()
。サーバーがクライアント要求を受け入れると、カーネルは追加操作のためにサーバーにランダムなポート番号を割り当てます。これは、send()
サーバーreceive()
の同じポート番号が送受信に使用できず、古いポートがまだ新しい接続を受信しているためです。
これらすべてを考慮すると、サーバーはどのクライアントがどのポートでデータを受信しているかをどのように知ることができますか?クライアントは送信元ポートと宛先ポートを含むTCPセグメントを送信することを知っているので、サーバーはそのセグメントの送信元ポートを宛先ポートとして使用しますが、サーバーはどのポートを見つけるためにそのポートを見つけるのですか?うんaccept()
?
答え1
これはパケットの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にあります)。リモートコンピュータが複数の接続を作成する場合、各接続は異なるリモートポートを使用します。したがって、リモートポート以外のすべては同じですが、大丈夫です。 4つのポートのうち1つだけが異なる必要があります。
たとえば、wirehsark を使用してパケットを表示でき、すべてのデータにタグが付けられます。以下は強調表示されたソースポートです(デコードされたパケットで強調表示され、下部の16進ダンプに注意してください)。
答え2
「接続要求(connect()
通常はクライアントプログラムのシステムコール)による三回の握手。 3方向ハンドシェイク(クライアントからサーバーへ)の最初のパケットにはSYNフラグが設定され、クライアントプログラムカーネルによって割り当てられたTCPポート番号が含まれています。
することができますNmapとNatural SYNパケットに関する記事。 Nmap SYNパケットのデコードには、「source.60058> dest.22」というフレーズがあります。デコードされた「正当なSYNパケット」には、「source.35970> dest.80」というフレーズが含まれています。これら2つのSYNパケットは、それぞれがTCPポート60058と35970から来たことをリモートカーネルに通知します。
答え3
TCPソケットはストリーム指向のソケットです。 2つのソケット記述子(あなたと同僚が所有する)が確実に接続されています。したがって、クライアントポートについて心配する必要はありません。ソケット記述子を作成するだけです!
また、本当に知りたい場合(おそらく記録のために)、自由にgetsockname(2)を使用してください。
答え4
接続はタプル(ソースIP、送信元ポート、宛先IP、宛先ポート)として定義されます。答えは正反対です。