• 締切済み

マルチスレッドチャットプログラム作成方法

マルチスレッドでチャットプログラムが組みたいです。 winsockを用いてVC++2010EEで組んでいます。 selectでのC/S型チャットプログラムは組めます。 マルチスレッドプログラムに関しては「猫でもわかるプログラミング」C言語編第1部第99章以降を参考にしました。 このサイトでのプログラムは分かるのですが、いざ自分のチャットプログラムに実装しようとするとどうすればいいのか分からなくなります。 やりたいこと(こうすればいいのだろうと思っていること)は winsockの設定 while(1) { ----SockBuf = accept(略); --------if( SockBuf != INVALID_SOCKET) --------{ ------------MaxClient++; ------------Sock.push_back(SockBuf); --------} ----thread()をSock[0]~Sock[MaxClient-1]ごとにスレッドで動かしたい。 ----その他の処理 } unsigned __stdcall thread() { ----recv(略) ----その他の処理 } どのようにしたらいいのか分からないので教えてください。

みんなの回答

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.3

ちょいと適当過ぎましたかねぇ…。 #2の疑似コードだと、 ・全クライアントへのsend()が完了するまで、共有メモリを保護しないとならない。 ・接続断の場合が考慮されていない。 などなど……。 まぁ、そこらへんはよろしく処理して下さい。ということで……。 考え方の1つの参考にでもして下さいな。 プロトコル次第っていうのもありますが。 Windowsであるかは不明ですが、IRCサーバのソースとかが参考に……なるかなぁ。 他のサーバとの同期処理とかは不要でしょうけどねえ。

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.2

>出来たらforループを使わずに、 どこからforループ出てきたのかが…… マルチスレッドとselect()だと http://x68000.q-e-d.net/~68user/net/c-echo-2.html とか参考になります…かねぇ。 クライアント側は現状で出来ているという「C/S型チャットプログラム」のままとして、 サーバ側では… accept()で作成されたソケットを専用のスレッドに渡して処理…でしょう。 発言内容を他のクライアントにも送信する為の「共有メモリ」(同一プロセスですからサイズ決めうちでもかまわんでしょう) 発言内容に設定完了を通知する「イベント」、 共有メモリのアクセス制御の為の「同期オブジェクト」などを用意して…… while(!EndFlag) {  FD_ZERO()  FD_SET()  select() //上記のFD_SETしたものを第1引数(受信確認)に、200ms程度でタイムアウトするように設定  if(FD_ISSET()) {   // 受信データ処理   // 受信内容に応じてもろろ処理  }  // 受信内容が発言内容ならば、同期オブジェクトで書き込み権限取得して、共有メモリに書き込み、イベントを設定する。  // 同期オブジェクトで権限取得出来なかったら、次のループの時に際取得。  // WaitForSingleObject()で発言内容のイベントが立ったら、send()でクライアントに送信する。 } ってな感じのループで処理できるんじゃないでしょうかね? # 発言内容設定完了イベントを誰がクリアするのか…とか、その辺りはもう少し考慮が必要でしょうけどね…。 # エラー処理とかそういうところは入っていませんが…よろしく処理して下さい。 >Sock[0]、Sock[3]、Sock[7] >から受信があったとしたら >3つのスレッド(プロセス?)が起動して処理が終わったら消え・・・・・ >というようなことがしたいのですが、 クライアントが切断するまではスレッドは生かしたままでいいと思いますけどね。 1発言(?)ごとにスレッド起こすのはムダでしょう。

  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.1

>selectでのC/S型チャットプログラムは組めます。 であれば…… 作成したスレッド中でしょりすればよいかと。 クライアント側はあくまでもサーバと1対1の通信のみにして、サーバ側で各クライアントからの発言を他のクライアントに送る。 ということになるでしょうね。 サーバ側をやったことはありませんので細かいところまでは不明ですが。 私がやったことあるのはクライアント側で、複数のPOPサーバとおしゃべりしてみましょう…って程度ですので。 # select()じゃなくてWSAAsyncSelect()でメッセージ処理してましたけど。 # 同期処理はちょっとハマりましたけどね。設計がイマイチだからですが。 英語ですが下記ページとか見てみてはどうですかね? http://msdn.microsoft.com/en-us/library/windows/desktop/ms738545%28v=vs.85%29.aspx Complete Winsock Server Codeで… // Accept a client socket で接続受けた後辺りから、 // cleanup のclosesocket()までがスレッドで処理する範囲になるでしょう。 送受信はselect()で面倒見る必要がありますし、 このサンプルでは早々にlisten()のソケット閉じていたりはしますが。 # SOMAXCONNのコネクション受け付けるようにしているわりには接続1個で閉じてる。

Null0lluN
質問者

補足

>作成したスレッド中でしょりすればよいかと。 済みません。もうちょっと詳しくお願いします。 出来たらforループを使わずに、 Sock[0]、Sock[3]、Sock[7] から受信があったとしたら 3つのスレッド(プロセス?)が起動して処理が終わったら消え・・・・・ というようなことがしたいのですが、

関連するQ&A

  • 多人数のチャットソフトを考えています

    winsockを使ってプログラミングしています。 1対1のチャットはできたのですが、サーバを挟んで1対多のチャットがうまくいきません。 サーバがクライアントごとにスレットを作って、acceptするたびにできるディスクリプタを配列に格納して、それを元に送信してきたクライアント以外に送るということをしたいと思っています。 説明下手ですいません。。。。 サーバ↓↓↓ ・・・・・・・・・初期化は略・・・・・・・・・・・・・・・・・・・・ while(1){ Csock[i] = accept(s,(struct sockaddr *) &Saddr, &Ssize); CreateThread(Csock[i]);  //クライアントごとにスレッドを作ってるつもり i++; } /**CreateThreadで作るスレッド**********/ unsigned __stdcall recvthread(void *lpx) //lpxにはクライアントのディスクリプタを格納 { fd_set fds, readfds; int sock = *(int *)lpx; int recvSize; char recvbuf[256]; FD_ZERO(&readfds); FD_SET(sock, &readfds); while(1) { memcpy(&fds, &readfds, sizeof(fd_set)); memset(recvbuf, 0, sizeof(recvbuf)); select(0, &fds, NULL, NULL, NULL); if (FD_ISSET(sock, &fds)) { WaitForSingleObject(mutex, INFINITE); recvSize = recv(sock, recvbuf, sizeof(recvbuf), 0); Send(sock,(const char)recvbuf); ReleaseMutex(mutex); if(recvSize == 0) { printf("通信終了\n"); closesocket(sock); break; } if(recvSize == -1) { printf("socket errer (recv)\n"); closesocket(sock); break; } } } return 0; } void Send(int sock,char recvbuf) { for(int j=0;j<5;j++) { if(Csock[j]==sock) continue; send(Csock[j],(const char*)recvbuf,sizeof(recvbuf),0); } } これを実行するとスレッドが無数に作成され、強制終了させられてしまいます。 初級者なのでプログラムのミスがあったら教えて下さい。 違うアイディアもあったら教えて欲しいです。見にくいと思いますがよろしくお願いします。。。。

  • 延々と受信し続けるwinsockのrecv

    以下のサーバープログラムを用いて、 (acceptしたらスレッド作成し、作成が終ったということをクライアントに知らせるために文字列送信後受信待機している) #include <winsock2.h> #include <vector> #include <process.h> #include <algorithm> char *Ver = "0.00"; using namespace std; unsigned __stdcall Patch( void *Sock ); int main() { ----WSADATA wsaData; --------WSAStartup( MAKEWORD(2,0), &wsaData ); ----SOCKET RecvSock = socket( AF_INET, SOCK_STREAM, 0 ); ----SOCKET SendSockBuf; ----vector<SOCKET> SendSock; ----fd_set ConnectFds, SubConnectFds; ----struct sockaddr_in Recv, Send; ----int len = sizeof(Send); ----Recv.sin_family = AF_INET; ----Recv.sin_port = htons(55555); ----Recv.sin_addr.S_un.S_addr = INADDR_ANY; --------bind(RecvSock, (struct sockaddr *)&Recv, sizeof(Recv) ); ----FD_ZERO( &SubConnectFds ); --------FD_SET( RecvSock, &SubConnectFds ); ----listen( RecvSock, 5 ); ----vector<unsigned int> thID; ----vector<HANDLE> hTh; ----struct timeval tv; --------tv.tv_sec = 0; --------tv.tv_usec = 0; ----while(1) ----{ --------memcpy( &ConnectFds, &SubConnectFds, sizeof(fd_set) ); --------select( 0, &ConnectFds, NULL, NULL, &tv ); --------if ( FD_ISSET(RecvSock, &ConnectFds) ) --------{ ------------SendSockBuf = accept(RecvSock, (struct sockaddr *)&Send, &len); ------------if( SendSockBuf != INVALID_SOCKET) ------------{ ----------------SendSock.push_back( SendSockBuf ); ----------------thID.push_back( hTh.size() ); ----------------hTh.push_back( (HANDLE)_beginthreadex(NULL, 0, Patch, &SendSock[hTh.size()], 0, &thID[hTh.size()]) ); ------------} --------} ----} ----closesocket(RecvSock); ----WSACleanup(); ----return 0; } unsigned __stdcall Patch( void *Sock ) { ----SOCKET *SendSock = (SOCKET *)Sock; ----send( *SendSock, Ver, 5, 0 ); ----char Str[5]; ----while( Flag == 0 ) ----{ --------recv( *SendSock, Str, 5, 0 ); ----} ----closesocket( *SendSock ); ----return 0; } 以下のようなクライアントプログラムで文字を送信すると、 #include <WinSock2.h> using namespace std; void main() { ----WSADATA wsaData; --------WSAStartup( MAKEWORD(2,0), &wsaData ); ----SOCKET Sock = socket( AF_INET, SOCK_STREAM, 0 ); ----struct sockaddr_in Addr; --------Addr.sin_family = AF_INET; --------Addr.sin_port = htons(55555); --------Addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); ----connect( Sock, (struct sockaddr *)&Addr, sizeof(Addr) ); ----char str[5]; ----recv( Sock, str, 5, 0 ); ----send( Sock, "0.00", 5, 0); ----shutdown( Sock, 2 ); ----closesocket( Sock ); } クライアントプログラムは終了しているのにサーバープログラムは"0.00"を受信し続けます。 どこがおかしいのか分からないので教えてください

  • C++でマルチスレッドによるネットワークプログラムを行いたいと考えてお

    C++でマルチスレッドによるネットワークプログラムを行いたいと考えております。 質問の内容は「どちらの方が速度的に有利か?」という二択です。 Linux、C++にてサーバープログラムを作成する予定で、実装したい内容は複数人の映像チャットのようなものをP2P型ではなくサーバー-クライアント型で行います。 1部屋で10人の通信を行うとして10部屋の通信を扱いたいです。(部屋の数は変動します) そこで以下の方法のどちらが効率的かを教えていただきたいです。 方法1 外部と通信するスレッドは1つで使用するポートも一つ(100人からの接続をポーリングで対処) 部屋の中身の処理をマルチスレッド化しておき通信システムが各部屋と情報をやりとりする 方法2 部屋ごとにスレッドを作成 各部屋(スレッド)が通信機能を持ち、ポートは部屋ごとに変える 方法1、2以外に、どちらも変わらないという選択肢でも構いません。 どうぞよろしくお願い致します。

  • マルチスレッド化。

    今とても大きな配列を使用し、長時間処理をするプログラムを組んでいます。元々処理時間に1時間を要するプログラムを2分で処理を完了するまでに仕上げました。 しかし、探究心はおさまらずもう少し高速化に挑みたいと考えています。 過去に「猫でもわかる」のSDK第1章と2章を学び、マルチスレッドのプログラムをSDKで組んだことがあります。それを利用してマルチスレッド化を実現したいと考えています。 言語はCでVisualStudio2005を使用しています。 *疑問1   SDKの場合WinMain関数とプロシージャからの実行で_beginthread関数を記述すれば処理が開始されます。 Cでもmain関数内に記述すれば、SDKと同様に処理できるのでしょうか? *疑問2 _beginthread関数の引数に関してです。 第1引数にvoid型のスレッド関数、第2引数に0?、そして第3引数にはスレッド関数に渡すデータの引数を記述すると把握しているのですが、渡したいデータは複数あり、***型と**型、それに変数を数個とスレッド関数に渡したいデータだらけなのですが、どのように記述すればよいでしょう? *疑問3 2つのスレッドを作成しようと考えていますが、その2つのスレッドで1つの大きな配列を共有して処理したいと考えています。 そのため、スレッド間の同期が必要になるわけですが同期の種類にもクリティカルセクションやミューテックス、イベントと豊富でどれを使用すれば良いのか迷ってしまいます。厳密に同期を取り処理をするにはイベントが一番良いと考えています。 これらの疑問に答えられる方はアドバイスをよろしくお願いします。

  • マルチスレッドプログラミングについて

    現在DirectXでマルチスレッドを使ってプログラムを組んでいますが、その処理の中で描画のみを切り離してスレッド化しようと思っています。 そこで質問ですが、描画スレッドに渡す処理の個数が多い場合は描画スレッドを2つにして処理する個数も分けたほうが処理は早くなるのでしょうか?

  • マルチスレッドでバグが発生します

    実際のプログラムでバグが出たので、簡易化したプログラムでテストしてみましたがどこが悪いのか分かりませんでした。 #include <WinSock2.h> #include <vector> #include <process.h> #include <algorithm> #include <stdio.h> using namespace std; CRITICAL_SECTION cs; unsigned __stdcall Login( void * ); int main() {     vector<unsigned int> thID;     vector<HANDLE> hTh;     for( int i=0 ; i<10 ; i++ )     {         printf( "メインスレッド:%d\n", i );         if( (i%2) == 0 )         {             thID.push_back( i );             hTh.push_back( (HANDLE)_beginthreadex(NULL, 0, Login, &i, 0, &thID[i]) );         }     }     while(1)     {         for( int i=0 ; i<10 ; i++ )         {             if( hTh[i] != NULL )             {                 CloseHandle(hTh[i]);             }         }         char a[2];         scanf( "%c", a );         if( strcmp( a, "X" ) == 0 )         {             return 0;         }     } } unsigned __stdcall Login( void *Num ) { int *a = (int *)Num; for( int i=0 ; i<10 ; i++ ) { printf( "サブスレッド%d:%d\n", *a, i ); } return 0; } 出るエラーは以下のようになります Windows によって Server.exe でブレークポイントが発生しました。 ヒープが壊れていることが原因として考えられます。Server.exe または読み込まれた DLL にバグがあります。 あるいは、Server.exe がフォーカスを持っているときに、ユーザーが F12 キーを押したことが原因として考えられます。 可能であれば、出力ウィンドウに詳細な診断情報が表示されます。 if( (i%2) == 0 ) をコメントアウトするとエラーは出ません また、共に 表示される例として(見やすいように空行あり) 以下のように、 スレッド番号が+1されていたり(A) 各スレッド内のループ回数が直前のスレッドの回数を引き継いでいたり(B) スレッドのループ回数が初期化されていたり(C) 呼び出されてないはずのスレッドが起動していたり(D) します メインスレッド:0 メインスレッド:1 サブスレッド1:0 ・・・・・・A(本来はサブスレッド0のはず) サブスレッド1:1 メインスレッド:2 サブスレッド2:3 ・・・・・・B(本来はサブスレッド2:0のはず) サブスレッド2:4 サブスレッド2:5 サブスレッド1:0 ・・・・・・C(本来は1:3のはず) サブスレッド1:1 サブスレッド2:0 サブスレッド3:0 ・・・・・・D(本来はまだ起動してないはず) サブスレッド3:1 メインスレッド:3 どこを直せばいいか教えてください

  • (マルチスレッド)_beginthreadexに複数の引数を渡す

    現在プログラムでマルチスレッドをやろうとしているのですが、 マルチスレッドの関数に数値や配列などの引数を渡すことは可能でしょうか? MSDNで調べてみると、_beginthreadex関数の4番目のNULLのところに引数リストを 指定できるとあったのですが、その意味が良くわかりませんでした。 以下のプログラムの場合にマルチスレッドに変数a, b, cを引数として渡したい場合は どのように書けばいいのでしょうか? #include <stdio.h> #include <windows.h> #include <process.h> unsigned WINAPI MyThread( void *lpx ){ while (1) { printf("スレッド実行中\n"); Sleep(1000); } return 0; } void main(){ // スレッドに渡したい変数の宣言 int a = 128; int b = 256; int c = 512; // スレッドIDの宣言 DWORD thID; // マルチスレッドの開始 (HANDLE)_beginthreadex( NULL, 0, &MyThread, NULL, 0, (unsigned int*)&thID ); // ループ while (1) { printf("メイン関数実行中\n"); Sleep(2000); } }

  • 親スレッドが子スレッドを監視する方法について(マルチスレッド)

    こんにちは。 私は、A端末から送信されたパケットをB端末で受信し、B端末で受信したそのパケットを再度、A端末へ送信するというプログラムを作成しました。 Phase1.A端末(送信側)→B端末(受信側) Phase2. B端末→A端末 ということです。 上記を実現するために、送信端末において、送信スレッド(親スレッド)と受信スレッド(子スレッド)を立てマルチスレッド処理を行っています。以下にプログラムの概要を示します。 main(int argc ,char *argv[]){ UDPSend(s_port,szServer); } static int UDPSend(unsigned short s_port,char *szServer){ hTh = (HANDLE)_beginthreadex(NULL, 0, UDPReceiveData, NULL, 0, &thID); while((n = fread(send_Buf,1,SEND_DATA_SIZE,fp)) != 0) { sendto(s1, send_Buf, n, 0, (LPSOCKADDR)&addrin1, sizeof(addrin1)); } } unsigned __stdcall UDPReceiveData(void *lpx){ while (1) { size = recvfrom(s2, recv_Buf, (int)sizeof(recv_Buf) - 1, 0, (SOCKADDR *)&from, &fromlen); return 0; } } UDPSend関数にて、パケットをB端末へ送信。UDPReceiveData関数にて、B端末からのパケットを受信しています。この場合、UDPSend関数(スレッド?)がUDPReceiveData関数より先に、終わってしまう場合が生じると思っているのですが。 UDPSend関数がUDPReceiveData関数を監視する方法があるのでしょうか? よろしくお願いします。

  • ソケット通信の受信処理について(マルチスレッド)

    今私はVisual Studio2010 C++で ソケット通信のプログラムをしているのですが、 クライアントから送ってくる文字をうまく受信できません。 接続は出来ています。 _beginthreadexでスレッドを作っています。 以下が受信の処理のスレッドになっています。 unsigned int __stdcall ThSend(void* pArg) {     CSocket_ServerDlg* pDlg = (CSocket_ServerDlg*)pArg; while(1){       char buf[256]; /* 受信するバッファ */ int buf_len; /* 受信したバイト数 */ buf_len = recv(pDlg->m_NewSoc,buf , RECVSIZE - 1, 0); if (buf_len != SOCKET_ERROR ){       buf[buf_len] = '\0'; /* 受信したバッファの後ろにNULLを付加する */       }       pDlg->m_xvEditResult += _T("Recv : ");       pDlg->m_xvEditResult += buf;       pDlg->m_xvEditResult += _T("\r\n"); } return 0; } "m_"はメンバ変数です。 以下がスレッド作成のソースになっています HANDLE hForth; unsigned int nForthID; hForth = (HANDLE)_beginthreadex(NULL, 0, ThSend , this, 0, &nForthID ); なぜ受信できないのか分からない状態です。 ではよろしくお願いします

  • 古いマルチスレッドプログラムはマルチコアに対応しているのか

    Windows上での話という事でお願いいたします。 HTが出始めた頃の高級言語C++やDelphi等で作成した、マルチスレッドプログラムは、そのままでマルチコアに対応しているのでしょうか? 多くの記事やネット上の情報およびインテルのQuad coreのプロモーションを見る限り、プログラムがマルチスレッドならば、そのままマルチコアを有効に利用できるような事が書いてありますが、プログラミングにおいて、特別にマルチコアに対応するようなコードは必要ないのでしょうか? C#用のQuad Core対応といったようなライブラリもあり、特別な処理が必要なのではという雰囲気がただよっているのですが・・・。 (ライブラリのソースまで見れたわけではないので、実態がよくわからない) Quad Core対応のライブラリというのは、いったい何をしていると予想されますでしょうか。 4スレッドで動く事を前提に最適化されているだけなのでしょうか。 といった疑問なのですが、お暇がありましたら ご回答いただければ幸いです。

専門家に質問してみよう