• ベストアンサー

WinSockでチャット

サーバーとクライアントで別プロセスで起動し サーバーに何人ものクライアントが接続をしに行っています。 チャットを作成するまでは出来たのですが 次に、サーバーに接続している全てのクライアントを ダイアログのリストボックスに 表示させたいと思っています。 現在接続している全クライアントをサーバーから取得する関数はありますでしょうか? 知っている方いましたら御教授お願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
  • piyo2000
  • ベストアンサー率49% (144/293)
回答No.3

#1です。 >TCPはトランスポートプロトコルです。 そのとおりです。すみません(^^; FTPって書いたつもり・・・だったんですけどね(笑) >プロトコルの作成方法がいまいち掴めなくて まず、TCPの特徴として ・データの送受信は保証される(UDPはされない) ・しかしデータの受信タイミングは一括とは限らない ということを覚えておきましょう。 例えばクライアントに「こんにちわ」という文字列を送信した場合、「こんにちわ」一発で届くかもしれませんし、「こんに」「ちわ」と2度で届くかもしれません。(こんなに短い文字列だとほぼ100%一発受信ですが) また「こんにちわ」「元気ですか」と2回送信した場合に「元気ですか」「こんにちわ」とひっくり返ることはありません(到着順序の保証)。 なので、プロトコルを作成する場合「どこからどこまでがデータの始まりで、データの終わり(ターミネータ)なのか」が分かればいいのです。 例えば#2さんの場合だと「CRLF(改行コード)」がターミネータのようですね。 逆に受信側ではバッファを見て「CRLF」までをワンブロックとして処理すればいいわけです。 プロトコルというと難しく感じますが、その名のとおり「データをどのように処理するか」という決まり事ですので、問題が無ければ別にどんな方法でも構わないんです。

maxpower-zero
質問者

補足

レス有難うございます。 プロトコル作成でスタックを使用しても問題は無いのでしょうか? 例えば std::stack<int> st; st.push( 10 ); st.push( 'あ' ); とスタックの中に入れて 送信; send(Sock,reinterpret_cast<char*>(&st),sizeof(st),0); 受信: recv(Sock,reinterpret_cast<char*>(&st),sizeof(st),0); 受信後にスタックの中を順に取り出し表示 cout << (int)st.top() << ", "; st.pop(); cout << (char)st.top() << ", "; st.pop(); これでも一応、始まりと終わりが判るとは思うのですか、 こういうのでも、プロトコルといえるのでしょうか? 宜しくお願いします。

その他の回答 (3)

  • piyo2000
  • ベストアンサー率49% (144/293)
回答No.4

>プロトコル作成でスタックを使用しても問題は無いのでしょうか? 問題ないと思いますけど・・・? ただ、スタックって基本的にFILO(先入れ後出し)な構造の時使うものなのでこの場合は不適ですよ。SocketのバッファはFIFO(先入れ先出し)なデータ構造と考えないと・・・。 >これでも一応、始まりと終わりが判るとは思うのですか、 わからない・・・と思いますけど。 >こういうのでも、プロトコルといえるのでしょうか? うーん、良く伝わってなかったようですね(^^; 最初の質問の「サーバーに接続している全てのクライアントを(各クライアントに)教える」という目的は置いておくとします(^^; 例えば、#2さんのアドバイスを流用して、クライアントは常に「ユーザー名<CRLF>メッセージ<CRLF><CRLF>」というデータ投げるようにします。こういうのがプロトコル(決まりごと)ですよ。 各クライアントはこれを(プロトコル通りに)解析するだけです。 ですので(最初の質問を無視するなら)サーバ側は各クライアントから送られたデータをそのままマルチキャストしてやれば良いだけ、ということになりますね。 そして最初の質問を実現するなら サーバ側からクライアントに「接続者全リスト」を送る必要は全く無く、各クライアントがリストを保持しておき、サーバから接続/切断情報を受け取った時にその都度更新する という方式のほうが(サーバが)軽くていいと思います。 で、クライアントが接続/切断した場合は 「svr<CRLF>ユーザー名<CRLF>接続状態<CRLF><CRLF>」 というデータをサーバから送る、とします。 クライアントは先ほどと同様にデータを解析しますが、先頭が「svr<CRLF>」で始まってますから、サーバからのメッセージだと言うことを理解できますよね。 (ユーザー名に「svr」を使わないのが前提ですが) ここまで書けば・・・分かると思うんですが(^^;

maxpower-zero
質問者

補足

レス有難うございます。 プロトコルは理解する事が出来ました^^; > 各クライアントがリストを保持しておき 最初の質問に戻ってしまうのですが クライアントがリストを保持するタイミングが判らないのですが・・・ 最初の接続時にサーバーから接続者リストをもらう訳ですよね。 サーバーは各クライアントのIPとポート番号はどうやって取得しておくのでしょうか? クライアントがサーバーに対して申告でしょうか? それとも otu_otuさんが仰るように サーバーのソケットのハンドルをクライアントに 渡せば良いのでしょうか?

  • otu_otu
  • ベストアンサー率31% (17/54)
回答No.2

 全クライアントをサーバから取得するとはどうゆうことでしょうか?  サーバはクライアントと接続されているわけですから、ソケットのハンドルを持っていますよね?そのハンドル自身がクライアントだと考えてはいけないのですか?  もし、クライアントにそれぞれ名前をつけたいのであれば(例えば「Hideya」とか「Goo」など)、まずクライアントからサーバにそれを教える手段を確保しなければなりません。  たとえば、接続の際に、次のような情報をクライアントから、サーバに送るといいでしょう。 Name: Hideya<CR><LF> <CR><LF>  サーバ側では接続が確立しているあいだ、その名前を保持させます。これで、サーバによるクライアント名の管理はできますよね。  一方で、maxpowerさんの目指しているのは、サーバに保持されているクライアント名のリストを、何らかの手段でクライアントから取得したいのですよね。  それであれば、クライアントからサーバに Who are login?<CR><LF> <CR><LF> と送り、それを受信したサーバが、 The Member Count: 12<CR><LF> Name: Hideya<CR><LF> Name: Goo<CR><LF>   ・   ・   ・ <CR><LF> のように、応答するようにしてはいかがですか?  TCP上でチャットシステムを作るのであれば、プロトコルを作成しなければいけません。  #1の方の補足ですけれど、HTTPは確かにアプリケーションプロトコルですが、TCPはトランスポートプロトコルです。

maxpower-zero
質問者

補足

>> 全クライアントをサーバから取得するとはどうゆうことでしょうか? マルチキャストを行いたいので、サーバーに接続している全てのクライアントの情報(IPや名前)を取得し 特定のクライアントにメッセージを送信するように したいと思っています。 TCP上でチャットを作りたいのですが プロトコルの作成方法がいまいち掴めなくて 困っています。。。

  • piyo2000
  • ベストアンサー率49% (144/293)
回答No.1

>現在接続している全クライアントをサーバーから取得する関数 それはサーバの仕事だと思いますが(^^; 少なくともサーバは「どのクライアントが接続(切断)したか」は知っているわけですから、サーバが各クライアントに必要に応じて情報を送ってやればいいのです。 >チャットを作成するまでは出来たのですが ただ単に文字列を垂れ流すだけ・・・になってるんではないでしょうか? いわゆる「アプリケーション層」のプロトコル(例えばHTTPやTCP)を設計すべきだと思います。 検索してみると・・・ http://www.ie.u-ryukyu.ac.jp/~j00043/network/protocol.html こんな感じでもいいですね。

参考URL:
http://www.ie.u-ryukyu.ac.jp/~j00043/network/protocol.html
maxpower-zero
質問者

お礼

>> ただ単に文字列を垂れ流すだけ・・・になってるんではないでしょうか? 仰るとおりです。 垂れ流しになっていると思います。 >> いわゆる「アプリケーション層」のプロトコル(例えばHTTPやTCP)を設計すべきだと思います。 WinSockを使えば、TCP/IPにの設計を気にする必要など ないと思っていました・・・

関連するQ&A