クライアント・サーバ方式でのソケット通信のしくみについて(MFC)

[戻る]
とよ 2010/01/16(土) 11:16:55
 VC2008(MFC)でソケット通信を行うアプリケーションを開発しています。(TCP/IP通信)
通信プログラムを組むのは初めてで分からないところだらけです。
 非同期通信(CAsyncSocketの派生クラスを作成)をしています。

 (質問内容)
 ポート番号のしくみについてなのですが、
・サーバー側は1つのポートを解放する。(OnAcceptイベント待ち状態)
  この状態で複数の接続要求(connect)が来ると、それぞれにソケットを用意して接続
 できますが、このとき、サーバ側は解放した1つのポート番号で複数の相手と接続でき
 ますよね?その後、SendやRecieveでデータを通信する時も「複数の相手に1つのポー
 トで対応する(通信する)」という解釈でいいんでしょうか?

・これに対してクライアント側はサーバ側のIPアドレスの解放してあるポートに接続
 (connect)する。
  クライアント側で使うポートは特に設定しなければ自動割り当てになります。この
 時、クライアント側のポートはサーバとの通信用に独占されているような感じを受け
 ますが(同じポート番号で再度connectできない)、これは「クライアント・サーバ方
 式」というもののルールによるものなのでしょうか?

 PCをサーバーとして使うと「1つのポートで複数とやり取り」ができ、クライアント
として使うと、「1つのポートでサーバとしかやり取りができない」のが何故なのかな
〜と思いました。ちなみにクライアント側の1つのソケットを2度同じポート番号で
CreateしてConnectすると、同じポート番号で2つの相手にconnectできました(デバッグ
でCreate時にASSETが出ましたが無視)。サーバ側のアプリを落とすと2度OnCloseが呼ば
れるのでつながってはいるんではないかと…。

 上記以外にも質問したい内容が多いので、以下にまとめます。

1.クライアント・サーバ方式の通信方法の1つとしてTCP/IPという規格があるとい
  う解釈でよろしいでしょうか?
2.それに対してP2P方式というのがあり、これは、それぞれがサーバ的な役割ができる
  (1つのポートで複数とやり取りができる)と思っているのですが正しいでしょうか?

  そもそも「ポートを解放する」という意味がいまいちピンときません。クライアント
側のポートはサーバ側のポートに「接続」はしても「解放」はしていないんですよね?
  P2Pでは、それぞれが1つのポートを解放し、その情報をサーバ的なところに開示し
て、誰からでもconnectしに行けるという感じなのでしょうか?

 支離滅裂な質問内容で大変申し訳ないですが、よろしくお願いします。

瀬戸っぷ [E-Mail] 2010/01/16(土) 14:40:45
>・サーバー側は1つのポートを解放する。(OnAcceptイベント待ち状態)
>  この状態で複数の接続要求(connect)が来ると、それぞれにソケットを用意して接続
> できますが、このとき、サーバ側は解放した1つのポート番号で複数の相手と接続でき
> ますよね?その後、SendやRecieveでデータを通信する時も「複数の相手に1つのポー
> トで対応する(通信する)」という解釈でいいんでしょうか?

解放という書き方だと誤解を招きそうですが……
特定のポート番号への「接続を待ち受け」している状態です。
で、接続があると個別にsocketを作成しますが、この時に「自分のIPアドレスとポート番
号」「相手のIPアドレスとポート番号」が紐付けされたソケットが作成されます。
で、この紐付けされたsocketに対してsend()やrecieve()を行うので、
別の相手との通信が混乱することはありません。
# 複数のファイルをオープンして、それぞれ読み書きしてもごっちゃにはならないですよね。

>・これに対してクライアント側はサーバ側のIPアドレスの解放してあるポートに接続
 (connect)する。
>  クライアント側で使うポートは特に設定しなければ自動割り当てになります。この
> 時、クライアント側のポートはサーバとの通信用に独占されているような感じを受け
> ますが(同じポート番号で再度connectできない)、これは「クライアント・サーバ方
> 式」というもののルールによるものなのでしょうか?

socketでの識別のため…でしょうか。
クライアント側のポート番号は未使用のものであれば何でもいいわけですし。
# クライアント側でもbind()すれば固定はできますが…1つしかbind()できませんし。
ちなみに、同じPCから複数のクライアントがサーバに接続しても、クライアント側のポー
ト番号が違いますので複数接続に問題はありません。
# HTTPなんかが1つのサーバに複数の接続を張ることがあります。
# FTPもちょっと特殊な接続を張りますが。


>1.クライアント・サーバ方式の通信方法の1つとしてTCP/IPという規格があるとい
>  う解釈でよろしいでしょうか?

そうなります。
他にも通信方式はいろいろある…とは思われますが、TCP/IPがほぼ標準…ですね。

>2.それに対してP2P方式というのがあり、これは、それぞれがサーバ的な役割ができる
>  (1つのポートで複数とやり取りができる)と思っているのですが正しいでしょうか?

概ね合っているかと思います。
が、P2Pに対してはあまり調べていないので細かいところは不明ですが。

とよ 2010/01/16(土) 15:29:31
 瀬戸っぷさん。回答ありがとうございます。
「解放」ではなく、「開放」でした。すみません…。

>で、接続があると個別にsocketを作成しますが、この時に「自分のIPアドレスとポート
>番号」「相手のIPアドレスとポート番号」が紐付けされたソケットが作成されます。
>で、この紐付けされたsocketに対してsend()やrecieve()を行うので、
>別の相手との通信が混乱することはありません。

 仕組みがなんとなくつかめてきました。
・サーバ側は接続要求のあったそれぞれのクライアントに対して「紐付けされたソケッ
 ト」を作成することで、1つのポートで複数の相手と通信している。
・クライアント側は1つのポートをサーバと紐付けし、対サーバ専用のポートとして使
 う。

 以上が「クライアント・サーバ方式」での通信ルールということですね。
クライアント側も1つのポートで複数のサーバと紐付けすることは可能だが、ルールによ
って「していないだけ」ということでしょうか?

 この方式での「利点」なども含めて勉強していきたいと思います。

aetos 2010/01/18(月) 10:57:52
> 1.クライアント・サーバ方式の通信方法の1つとしてTCP/IPという規格があるとい
>   う解釈でよろしいでしょうか?
> 2.それに対してP2P方式というのがあり、これは、それぞれがサーバ的な役割ができる
>   (1つのポートで複数とやり取りができる)と思っているのですが正しいでしょう
か?

クライアント・サーバ方式というのは、一般的にはクライアントとサーバの役割が明確
に分かれているものを言います。
P2P方式はすべてのマシンがクライアントでありサーバでもあります。ですから、P2Pは
一般的にクラサバ方式とは言いませんが、P2Pにもクライアントとサーバがあります。
TCP/IP はどちらにも使える汎用的な通信規格であって、特にクラサバ方式のためのもの
ではありません。

> そもそも「ポートを解放する」という意味がいまいちピンときません。
> クライアント側のポートはサーバ側のポートに「接続」はしても「解放」は
> していないんですよね?

ポートの開放というのはファイアウォールに穴を開けることですよね。
FW を開けていなければ接続できないのであらかじめ開けておく必要はありますが、プロ
グラムで bind なり accept なりする作業のことを「開放」とは呼ばないでしょう。
FW は一般的に、外から自分のマシンに接続する(インバウンド接続)のを制限すること
が多いです。このため、外(クライアント)からの接続を受けるサーバでは開放する必
要がありますが、外(サーバ)へ接続していく(アウトバウンド接続)クライアントで
は開放作業は必要ありません。
ただし、アウトバウンド接続も制限する FW を使っていたら、クライアントでも開放作
業が必要です。

> P2Pでは、それぞれが1つのポートを解放し、その情報をサーバ的なところに
> 開示して、誰からでもconnectしに行けるという感じなのでしょうか?

そうですね。
たとえば Winny に代表されるファイル共有ソフトなどは、最初に Web サイトに公開さ
れている「ノードリスト」というのを取り込みます。
このノードリストに、接続を待ち受けているマシンの IP アドレスとポートが書かれて
います。
そうして一旦ネットワークに参加したら、あとは隣接するノードから別のマシンのアド
レスとポート番号を受け取ったりすることもできるでしょう。

仲澤@失業者 2010/01/18(月) 17:52:41
他の回答者の皆さんが発言している通りですが、簡単に言うと

1.「サーバーソケット」を作ってlisten()しているのがサーバー
2.「クライアントソケット」を作ってサーバーにconnectするのがクライアント
3.listen()中にconnectされたサーバーはaccept()し「アクセプト済みソケット」
 を取得する。
4.以後サーバーは「アクセプト済みソケット」で、
 クライアントは「クライアントソケット」で通信が可能。
5.サーバーはaccept()するたびに「新しい」「アクセプト済みソケット」が
 作られるので複数のクライアントを対象とできる。

MFCの場合は、一般に「サーバーソケット」=CAsyncSocket、
「クライアントソケット」=CSocketで作れます。

毎度おんなじことを言うようで申し訳ないですが、CSocket以下の一連の
MFCソケットクラスを使用するのはやめたほうがいいです。
これは、CSocketがCObjectから派生しているという、根本的な設計ミスが
原因なのでどうしようもありません。バークレーコードで書きましょう。

TCP/IPは通信の規格、クライアントサーバーやP2Pは情報伝達方法の仕組みの
種別名称なのであって両者は無関係。このぐらいは先に調べておかないと先が
思いやられます。老婆心であってほしいですが(vv;)。

とよ 2010/01/19(火) 18:36:58
 aetosさん、仲澤@失業者さん、ありがとうございます。

 ファイアウォールと関係があるとは知りませんでした。今回初めて通信について勉強
するので、知らないことだらけで恐れ入ります。

 
>  MFCの場合は、一般に「サーバーソケット」=CAsyncSocket、
> 「クライアントソケット」=CSocketで作れます。

 僕はサーバもクライアントもCAsyncSocketで組んでいますが、クライアントはCSocket
で組むほうがよいということでしょうか?CSocketで組むとデータ受信はタイマー内で
Recieve関数を呼び出し、その戻り値からデータ内容を振り分けていくことになると思い
ますが、「クライアントソケットはCSocketで作った方がいい」という理由があれば教え
てもらえますか?

仲澤@失業者 2010/01/20(水) 09:35:31
>ますが、「クライアントソケットはCSocketで作った方がいい」という理由があれば教>てもらえますか?

特にありません。単に「できてしまう」だけです。
「クライアントサーバー」の説明の都合上あえて
別にしてみただけと読み取ってください。

とよ 2010/01/26(火) 09:08:24
[[解決]]
 仲澤@失業者さん、ありがとうございました。
返事が遅れてすみません。インフルエンザで寝込んでしまってですね…。。
通信の仕組みについて、しっかり勉強していきたいと思います。

古いスレッドには追加発言できません。