web-dev-qa-db-ja.com

TCPでbind()が使用されるのはなぜですか?なぜサーバー側でのみ使用され、クライアント側では使用されないのですか?

TCPのbind()の正確な機能を知りたかった。ソケットにローカルアドレスを「バインド」することはどういう意味ですか?ソケットにポート番号を割り当てている場合、クライアントでそれを使用しないのはなぜですか?ポートはクライアントサイドでOSによって自動的に割り当てられることは知っていますが、このすべてがどのように機能するかについての全体像はわかりません。

Bind()の後、listen()します。バインドはlisten()とどのように関連していますか? listen()はbind()が実行されたことを知っていますか?もしそうなら、bind()はどのような変更を加えて、それが知られるようにしますか?つまり、実行を成功させるためにゼロを返すにはどうすればいいですか?

私は多くの定義を経験しましたが、これらすべてを詳細に入手できる場所はありませんでした。だから誰かが私にこれを説明してもらえたら感謝します。

44
Crocode

「ローカル」エンドのポート番号を割り当てます。

サーバーソケットの場合、これが最終的な方法です。まさに、必要なものです。たとえば、ソケットをWebサーバーのポート80にバインドします。

ただし、クライアントソケットの場合、ローカルアドレスとポートは通常重要ではありません。したがって、bind()はしません。サーバーが特定のポート番号または特定の範囲外のポート番号を持つようにクライアントを制限している場合は、クライアント側でもbind()を使用できます。

一方、listen()を呼び出していないソケットでbind()を実行できる場合もあります(実際にはそれについてはわかりませんが、意味があります) )。このシナリオでは、サーバーポートはランダムであり、サーバープロセスは別の方法でクライアントにポートを通信します。制御接続とデータ接続があるFTPなどの「二重接続」プロトコルを想像してください。データ接続がリッスンするポートは完全に任意ですが、反対側に通信する必要があります。したがって、「自動的に決定されたポート」が使用され、通信されます。

Pythonの1つの例:

import socket
s = socket.socket() # create your socket
s.listen(10) # call listen without bind
s.getsockname() Which random port number did we get?
# here results in ('0.0.0.0', 61372)

s2 = socket.socket() # create client socket
s2.connect(('localhost', 61372)) # connect to the one above
s3, x = s.accept() # Python specific use; s3 is our connected socket on the server side
s2.getpeername()
# gives ('127.0.0.1', 61372)
s2.getsockname()
# gives ('127.0.0.1', 54663)
s3.getsockname()
# gives ('127.0.0.1', 61372), the same as s2.getpeername(), for symmetry
s3.getpeername()
#gives ('127.0.0.1', 54663), the same as s2.getsockname(), for symmetry
#test the connection
s2.send('hello')
print s3.recv(10)
20
glglgl

bind()は、接続のローカルポートとインターフェイスアドレスを定義します。 connect()は、以前に実行されていない場合は暗黙的にbind("0.0.0.0", 0)を実行します(ゼロは「any」として扱われます)。

発信接続の場合、これは一般に受け入れられ、推奨されます。 OSは単に「すべてのインターフェイス」にバインドし、番号の大きい未使用のポートを選択します。サーバーが特定のポートまたはポート範囲から来ることを期待している場合にのみ、クライアントでバインドする必要があります。一部のサービスでは、スーパーユーザーのみがバインドできる1024未満のポート番号からの接続のみが許可されていますが、最近では誰もが自分のマシンを制御しているわけではありません。

着信接続の場合は、既知のポートにバインドして、クライアントがあなたに連絡する場所を知る必要があります。そうすると、サーバーにローカルアドレス/ポートが与えられ、通信が双方向に流れるようになります。 listen()は、bind()呼び出しの後のみ機能します。

すべてのソケットは、UDP、TCP、その他のいずれであってもバインドする必要があります。常に明示的に行われるわけではありません。

10
Brian White

ソケットをアドレスに「バインド」します。そうしないと、リッスンするアドレス(IPアドレスとポートのペア)がわかりません。

また、bindはクライアント側でも使用できます。 1つの例は、同じネットワークに接続された複数のネットワークカードを備えたコンピューター上にありますが、クライアントは特定の1つのネットワークアドレスからのものとしてのみ見られます。

バインディングは、TCPソケットだけでなく、UDPソケット、および他のプロトコルにも使用されます。

これは古い質問ですが、新しい答えがあります:)

IPごとに限られた数の着信接続のみを許可するサーバーに接続したい場合があります。

複数のネットワークインターフェースカードがある場合(したがって、複数の発信IPから接続できる場合)、bind()を使用して、各IPを手動で循環させ、接続のバランスを取るため、接続の数倍そうでなければ許可されます。

インターフェイスとIPのリストを取得するには、 this answerを参照してください。

0
BenGoldberg