お世話になります。
TCP通信処理をコーディングしていて疑問に思ったので質問させていただきます。内容的
にはC++から少し外れるかもなのですが。
1対多の通信でサーバ側は特定のポートで待ち受けをしており、クライアントからのコネ
クト要求によってOSが任意のポートに割り振りをしてサーバクライアント間でコネクショ
ンが確立します。200クライアント程接続したとき、サーバ側で他のアプリケーション
が使用したいポートがクライアントとの接続に使用されてしまいました。
このような重複はどうすれば回避できるのでしょうか。PGで自動割り当ての範囲を指定、
なんてのは無いですよね?。思ったのは、SERVICESファイルに定義されたポートは自動割
り当てから除外される?なのかなぁというところですが、割り当てされない、という検証
も確実にできないので。
以上、よろしくお願いします。
unixやlinuxでは設定で自動で使える範囲を一つ指定できる
複数の範囲を指定できるOSもある
Windowsはどこにその定義があるのか知らない
いろんなポートが使われているから難しいよね
たしかbind()を使うと固定(指定)出来た気がします。
自信がないので確認してみて下さい。
「bind socket」
http://www.google.co.jp/search?q=bind%E3%80%80socket&sourceid=navclient-ff&ie=UTF-8&rlz=1B3GGGL_jaJP282JP282&aq=t
wclrp様、とり様
早速のご回答、ありがとうございます。
確かにbind関数でポートは指定できますよね。私もINADDR_ANYしか指定したこと無いので
すが(^^;。
10個程度のクライアント端末であれば個別にポートを定義しておいて指定するのは問題な
いのですが、200程度ともなると大変な為、基本はOSにあいているポートを自動選択させ
たいと考えています。でも、自動割り当てされると困るポートがあるわけで・・・。なん
かないのかなぁ・・・。
強引ですが、使用予定で、OSに割り当てされては困るポート番号を well-known
ポートから選択するというのはどうでしょうか?
もちろんシステムで使用できるかどうかの確認、条件設定が必要になります。
ただ、一般にはサーバが待ち受けに使用するポートをbindで指定し、その後
acceptで接続待ちになると思うのですが、その後OSが自動当てするポートと
いうのは何なのでしようか。参考までに教えていただけますか。
サーバ側は全てのクライントに対し、同じ番号のポートを使用する思ってい
ました。プログラムはacceptが返すソケットを使うだけで、待ち受けの
ポートと別のポートが割りあたるかどうか気にしたことがありません。^^;
サーバー側TCP/IPソケットではアドレスにバインドされたソケットを使います。
サーバー側ではこのソケットをlistenしており、このソケットにconnectしてきた
クライアントに対してacceptします。acceptするたびに異なったint値が戻ります
(一般にアクセプトソケットと言います)。
一般にはこのアクセプトされたソケットがサーバー側の送受信ソケットに
なるわけです。
従って、一般的なサーバーコードにおいては、ご懸念の事態は発生しません。
サーバーコードはクライアントコードとは全くことなるものであることを
確認するため、一度書いてみることをお勧めします。
dogatana 様、仲澤様
>ALL
お世話になります。
申し訳ありません。現在出張中で仕事の合間に書き込みしていたものですから、少し考え
がまとまっていない状態で間違った内容を書いてしまいました。
試験として、クライアント端末からサーバ端末に200個のTCPコネクトを行いました。
クライアント側はポートを自動選択にさせています。その結果、任意200個のポートがク
ライアントソケット用として使用されますが、その後に起動するアプリが使用するサーバ
ポートとかぶってしまいました。
上記内容であってると思うのですが ^^;;;。
自前のアプリが使用する予定であるポートをリザーブしておきたいというのが質問の趣旨
です。
well-knownポートはできれば使用したく無いかなぁと思います。気持ちだけの問題かもし
れませんが、皆さんはどうでしょうか。
以上、よろしくお願いします。
> 上記内容であってると思うのですが ^^;;;。
あっていると思いますね。
> 自前のアプリが使用する予定であるポートをリザーブしておきたいというのが質問の
> 趣旨です。
たぶんOSで設定しないと無理だと思います。
普通のWIN XP(プロフェッショナル版ですが)見当たりませんね。
「サーバーOS」か、もしくは「専用のソフト」が必要かも知れませんね。
ポート番号xxxxに対しconnectしたクライアント側で
「netstat -a」コマンドで調べてみたら
TCP (クライアント):nnnn (サーバーIP):xxxx ESTABLISHED
ってな感じで、クライアント側のポート番号は、
サーバー側でListen用のソケットのポート番号とは無関係のポート番号ですね
acceptするとソケットが作られるとしか意識してなかった
そゆことでしたか。完全に読み間違ってました。
役に立たなくてすみません。
リザーブはできそうに無いので、サーバーアプリ側が
オンデマンドでポート番号を供給する仕組みを考えるとかかなぁ
・・・う~む(vv;)。
1対多でつなぐとしても
クライアントPC1台につき、クライアントソフトは1つもしくは少量ではないのでしょう
か?
PC一台につき1ソフトなら、自動割当せず、固定ポート番号でやればいいし
複数だとしても、使用したいポート番号の最小値、最大値あたりを決め
/********************************************/
port = 最小値-1;
while( !ret && port < 最大値 ){
port++;
ret = /* portで接続用ソケットを作成 */;//使用されてりゃ失敗
}
/*ここでサーバーにコネクト*/
/********************************************/
こんな感じで、使用したいport番号をズラしながら接続していくのはどうでしょう?
お世話になります。ご回答、ありがとうございます。
ITO様
>たぶんOSで設定しないと無理だと思います。
私もやるとすればOS側かなぁと思っています。SERVICESファイルに書いたものがリザーブ
されないかなぁと思っていたのですが、やはり名前参照の為だけのものなんでしょうか。
以下はSERVICESファイルの中の一行ですが
ms-sql-s 1433/tcp #Microsoft-SQL-Server
上記の定義であれば1433は自動割り当てされることはない、というのが理想ですが。
~~~~~~~~~~~~
週末になれば試験ができるので、だめもとでやってみようかと思います。
仲澤様
こちらこそ、間違った情報で混乱させてしまいました。すいませんでした。
自身が管理していない他の通信アプリがポート自動割り当てにより、自身の使用予定であ
るポートを使ってしまう、ということが防げればいいなぁと思っています。他のアプリが
サーバポートに使ってしまうようなケースは初期の環境作成の段階で発生しないように考
慮するべきことと思いますので。
自身で管理していない他のアプリに対しては、ポート情報を伝えるような手段はないなぁ
というところです。
rin様
>1対多でつなぐとしても
>クライアントPC1台につき、クライアントソフトは1つもしくは少量ではないのでし
実際には多対多通信・・・といいますか・・・。
全ての装置で同一のポートでListenしています。
装置A 装置B
Listen(2000) ←-------- コネクト
コネクト --------→ Listen(2000)
上記のように2装置間で見れば2本の通信パスを持つことになります。
これが200~300装置程度に拡大したところを想像していただければ・・・。
実際、業務でどのように使うかは別として、このような相互接続する通信の仕組みを作っ
た場合に、ポートを大量に使用するので、その他の業務アプリが使用する予定のポートと
かぶらないようにしたいなぁと思った次第です。
>複数だとしても、使用したいポート番号の最小値、最大値あたりを決め
なるほど。この方法は使えそうですね。使用するポート番号の範囲を定義ファイル化して
おけばいいだけですし、通信アプリ側も軽微な修正でいけそうですね。試してみたいと思
います。
Windowsの場合、1000番台(1024からだでしょうか)から割り当てられる模様
で、2000とかだと使用状況によって、クライアント側がサーバに接続する際のポート
に割り当てられてしまうかもしれませんね。
ただこれはWindowsの場合で、組み込み用の某RTOSだと65000番台から小さくなる方
向に自動割付してました。
サーバが使用するポート番号について、身近のアプリ(特殊用途向け)を調べてみました
が、5000番台と大きな番号でした。もちろん、設定で変更できます。
このあたりだと両方から攻められても実用上は問題ないかと。
試してませんが、Windowsではレジストリに登録して予約ができる模様。
http://www.microsoft.com/japan/technet/community/columns/cableguy/cg1205.mspx
> 私もやるとすればOS側かなぁと思っています。SERVICESファイルに書いたものが
> リザーブされないかなぁと思っていたのですが、やはり名前参照の為だけのもの
> なんでしょうか。
> 以下はSERVICESファイルの中の一行ですが
> ms-sql-s 1433/tcp #Microsoft-SQL-Server
これは、システム予約ですね。
メールの送受信、FTP送受信等ウインドウが標準で使うポートの定義ですね。
るしさんが示した例は、
「ms-sql-s」というウインドウ標準サービスで使用するポート「1433」という
ことになると思います。
つまり、「1433」というポートは、
「ms-sql-s」というサービスで使う。
ということになります。
お世話になります。
servicesファイルへの定義でポートを予約できるか試験してみました。
以下のようにservicesファイルに自分の予約したポートを定義します。
myapp 52300/tcp #My App
その後、この端末で300個のサーバーポートを開き、他の端末から300個
の接続を行ってみたところ、netstatの表示結果が以下のようになりました。
TCP home31:3125 192.168.3.2:52298 ESTABLISHED
TCP home31:3126 192.168.3.2:52299 ESTABLISHED
TCP home31:3127 192.168.3.2:myapp ESTABLISHED
TCP home31:3128 192.168.3.2:52301 ESTABLISHED
TCP home31:3129 192.168.3.2:52302 ESTABLISHED
やはり、servicesファイルに定義しただけではポートの予約なんてことは
できないんですね。
ITO様
>これは、システム予約ですね。
システム予約=「自由に割り当てしないように予約する」と思いたいのですが
実験結果を見た限りではそうでもないような気がしました。
で、ためしにFTPサービスを起動していないパソコンでFTPポート(21)を使って
TCPサーバポートを開いてみのたですが。
※netstatの表示
TCP home31:ftp home31:0 LISTENING
Listen状態になりました。
特定のポートを使用できるアプリを限定するとなると、ポートを開こうとし
ているアプリが何者なのかをOSが確認する手段が必要になるわけですよね。
そんな仕組みは聞いたことがないということは・・・。
どのアプリでも早いもの勝ちでポートを確保できるのはある意味、当然の
ことなのかな・・・と思いました。
結果、servicesファイルへの定義はポート番号とそのポートを使いたい「サービス
名称」の引当のみであり、ポートの実際取得は早いもの勝ちのように思います。
dogatana 様
レジストリにそのような定義があるのですね。
少しあとで試験してレポートします。
情報ありがとうございました。