ソケットの上限について

こんばんは。

「ネットワークはなぜつながるのか 第2版」を購入しました。
非常に分かりやすい内容で、多くの基礎知識を習得できました。

早速なのですが、1点お聞きしたいと思います。
第6章 P392~P393でクライアントから接続を受け付けると
新たなタスク/スレッドを生成するとあるのですが、ここで意味する
タスク/スレッドとは、

新たにアプリケーションのソケットを生成する(ftp 21など)ことをタスク。
同じアプリケーションでも、送信元ポートが異なるソケットを作成することを
スレッドという意味になりますでしょうか?

また、作成されるソケットには上限があるのでしょうか?
さらに、アプリケーション毎に上限があるのでしょうか?

どうぞ宜しくお願いいたします。

名前: 
YT
日時: 
10/01/16 00:01

コメント

YTさん、はじめまして。
拙著お読みいただきありがとうございます。

タスクとかスレッドっていう言葉はOSの用語です。
マルチタスクとかマルチスレッドとかいう言葉聞いたことありますか?
あのタスクやスレッドのことです。
正確に意味を理解するにはOSの基礎的な知識が必要で、
説明が長くなっちゃいますから(OSの入門書になっちゃうかも)
この場ではご勘弁ください。
GoogleとかWikipediaなどで調べてみるとよいでしょう。

で、392ページ近辺で使っているタスクとかスレッドという言葉は
このOS用語のタスク/スレッドと同じ意味で、
コンピュータの内部で動く一つ一つのプログラムのことを指します。

タスク/スレッドという風に併記してあるのは、
図6.1にある『(b)クライアントとやり取りする部分』を
タスク(プロセスという言葉を使う場合もあります)で実現する場合と
スレッドで実現する場合の両方があるので、二つを併記しているわけです。

なお、タスクで実現するか、スレッドで実現するかは、
性能をはじめとしたいろいろな事情を考慮して、
サーバプログラムを作る人が判断します。
タスクとして動くようにプログラムを作るか、
スレッドとして動くようにプログラムを作るか、
プログラムを作る人が決めるということですね。

それから、ソケットの上限に関係するのは
(いくつまで作れるかという数の問題ですよね?)
次の三つの要素です。

一つはソケットに割り当てるポート番号です。
ポート番号は16ビットですから、最大で65536個の値しかとれません。
クライアント側のポート番号はそれぞれが違う値にしなくてはいけないので、
クライアント側のソケットは65536個が上限になります。
なお、サーバ側のソケットは同じポート番号を割り当てることもできるので、
クライアント側より多数のソケットを作ることができるはずです。

もう一つは、OSのソケットテーブルの上限です。
こちらはOSの作り方によって違うでしょう。
個々のOSがいくつ、という数は私も知りません。

そして最後はメモリ容量です。
ソケットを作るとメモリを消費しますから、ソケットの数が多くなるとメモリがなくなります。
ポート番号の上限も、ソケットテーブルの上限も、十分に大きな値ですから、
実際の上限はメモリ容量によって決まると思って良いでしょう。
ソケットをたくさん作るっていうことは、
プログラムがたくさん動くっていうことでもありますから、
その面でもメモリが足りなくなるでしょう。
メモリがなくなる前に動作速度が低下して使い物にならなくなる、
という結果になるかもしれません。

丁寧な解説ありがとうございました。

ところでサーバ側の話になるのですが、、、
確認したい点が2点ほどありまして、またご教授願いたいと思います。
1).
P392にて
サーバプログラムを起動して、設定ファイルの読み込みなどの初期化動作を終わったところで、
接続を待ち受ける部分を実行します。
とありますがこれは基本的に、
・サーバOSが起動したとき
・サービスを手動で開始したとき
などでよろしいでしょうか?

2).
また、サーバは時としてクライアントにもなると思います。
この場合、サービステーブルに登録されてあるポート番号(well known除く)は、
クライアントとして通信する際、ポート番号として割り振られないという解釈で
よろしいでしょうか?
または、サービス開始されてなければ、ポート番号として割り当てられますでしょうか?

宜しくお願いいたします。

まず、(1)から行きましょうか。

> ・サーバOSが起動したとき
> ・サービスを手動で開始したとき
> など...

という理解で良いでしょう。
サーバプログラムを起動する方法はいろいろありますが、
どの方法で起動してもサーバプログラムの動作は一緒ですから、
どんな格好で起動しても同じように考えていいと思います。

次に(2)の方ですが、
そもそも『サーバ』っていうのは、
サーバプログラムを動かすからサーバとして動作しているだけであって、
OSやハードウェアがサーバとして動作しているわけではありません。
サーバ向けに最適化されたOSとかハードウェアというのはありますけど、
基本的な仕組みの面から見たときには、
OSやハードウェアには、サーバもクライアントも無い訳です。
だから、クライアントパソコンでサーバプログラムを動かして、
サーバとして使うこともできます。(性能面の問題はあるかもしれませんが)
というわけなので、サーバプログラムの動きはどうなのか、
クライアントプログラムを動きはどうなのか、
という視点で見た方がいいですね。

それで、ポート番号を割り当てる件ですが、
ポート番号そのものにはサーバとクライアントの区別はありません。
ポート番号を割り当てるソケットには、
接続を待ち受ける側(recipient)なのか、
接続しに行く側(initiator)なのか区別が必要です。
接続を待つか、接続しに行くか
という動作の違いを制御する必要があるからです。
しかし、ポート番号の方は、
本来、ソケットを識別するための単なる番号に過ぎないので、
サーバもクライアントもありません。
個々のソケットを識別できさえすれば、何番でもいいんです。

ただし、OSによっては特定のポート番号(例えば1024番以下)を
使う際には特権が必要になる場合があります。
(特権についてはOSの解説を参照してください。)
その場合は、プログラムに特権ポート番号を使う権限を与えないといけません。
この特権という考え方自身は、本来、
サーバとかクライアントとかとは関係ないのですが、
サーバプログラムには特権を与えて特権ポート番号を使うという例が昔は多かったので、
特権ポート番号はサーバ用というやり方が慣習化していました。
しかし、今ではサーバプログラムの種類が増えてしまい、
1024番には収まらなくなってしまったので、
1024番以下はサーバ用という慣習は崩れています。

で、この慣習から1024番以下のポート番号をwell-knownポートと呼ぶ場合もありますが、
本来のwell-knownの意味は少し違います。
well-knownというのは、皆が知っているということです。
つまり、サーバ側のポート番号は皆が知らないといけませんから、
サーバ側で使うポート番号を登録制にして、
その登録状況を見ることで皆にポート番号がわかるようにするという意味です。
これが本来のwell-knownの考え方です。
こちらは人間の制度というかルールの問題であって、
先ほどのOSの特権のような、機械側の機能や制約に関係するものではありません。

丁寧な回答ありがとうございました。

1).
分かりました。

2).
申し訳ありません。
少し具体的に質問させていただきます。

例えば、
クライアント→全銀TCP(5020)→中間サーバ→FTP(21)→顧客サーバ
という流れがあるとします。

中間サーバはサービスとして5020が登録されています。
ですので、1).のとおり、起動時にポート5020として接続を待ち受ける状態に
なると思います。

この中間サーバはクライアントから受け取ったデータを顧客にFTPで伝送します。
このとき、送信元ポートはランダムで割り振られますが、「接続を待ち受ける
状態にある」5020は割り当てられないという解釈でよいか?
というのが確認したかった点です。
また、サービスが開始されていなくても、サービステーブルに追記されたポート
は割り当てられなくなるのか?という点も併せてお願いしたいと思います。
OSの仕様によって異なるかと思いますが、特にWindowsで知りたいと思います。
分かる範囲でご回答頂ければと思います。

どうぞよろしくお願いします。

> クライアント→全銀TCP(5020)→中間サーバ→FTP(21)→顧客サーバ

こういう風に何台か繋がっていると、それぞれが関連あるように思うかもしれませんが、
TCP/IPの通信動作は別々になります。
つまり、
・クライアント→全銀TCP(5020)
・全銀TCP(5020)→中間サーバ
・中間サーバ→FTP(21)
・FTP(21)→顧客サーバ
という四つのTCP/IPの通信動作が別々に動きます。
そして、各マシンで動くプログラムがその間に入って、データを仲介するわけです。
絵にすると、

---> ソケット-プログラム-ソケット ---> ソケット-プログラム-ソケット --->

こんな感じでしょうか。
中間サーバには全銀TCPからの接続を受け付けるソケット(recipient)と
FTPに接続するためのソケット(initiator)の二つが存在することになり、
それぞれが別々に相手と通信動作を実行することになるんですね。
そして、recipientのソケットには、適当に固定的な値(5020かな?)のポート番号を割り当て、
initiatorのソケットには適当に空いている値を動的に割り当てるのが普通です。

それから、ソケットにポート番号を割り当てるところの動きですが、
それはこんな感じになります。
(1)ソケットを作ると、それがソケットテーブルに新しいソケットとして追加される。
(2)ソケットにポート番号を割り当てると、それがソケットテーブルに登録される。
[(1)と(2)を一緒にすることもあります]
(3)接続動作を実行する
その辺は『ネットワークはなぜ...』の75ページ以後に書いてあります。
そして、ソケットテーブルに登録された時点でそのポート番号は使用済みとなり、
他で使えなくなります。
接続動作が始まっていなくても使用済みになるわけですね。
この辺の考え方はWindows系でもUnix系でも同じです。
ただ、プログラミング言語によってプログラムの作り方に若干差が出ることはあります。

こんばんは。

>そして、recipientのソケットには、適当に固定的な値(5020かな?)のポート番号を割り当て、
>initiatorのソケットには適当に空いている値を動的に割り当てるのが普通です。

中間サーバはrecipientのソケットで固定的に5020を使用するので、initiatorの
ソケットには5020が割り当てられないということで理解しました。
ありがとうございました。

さて、本編とは関係あるのですが、一件ご教授お願いしたい点があります。

・クライアント→全銀TCP(5020)
にて、ある特定の送信元ポートのときのみ、サーバ側でどうやらacceptが失敗する
ことがあるようです。
ネットワークなぜ~では、クライアントから送信されたパケットの送信先ポートが
サーバ側で用意できていない場合はエラーを返すと(P407)あるのですが、送信元の
ポート番号の影響で失敗する原因でなにか考えられることはありますでしょうか?

宜しくお願いいたします。

特定の送信元ポートだとacceptが失敗するんですか。
既に同じ送信元ポートと接続済み、ということ以外には
これ、という答えは思い浮かびませんねぇ。

トラブルの原因究明の際に、
起こっている現象を正しく捉えているかどうか
(たとえば、本当にacceptが失敗するのか、
acceptに至る前にエラーになってしまうのか、など)
というところから始めなくてはいけないので、
こういう場での応対で解決するのは難しいと思います。

パケットの内容とか、もう少し詳しい情報があれば
原因の候補が思い浮かぶかもしれませんけど。