ソケット通信受信処理についての疑問

このQ&Aのポイント
  • Visual Studio2010 C++でソケット通信のプログラムをしていますが、クライアントからの文字受信がうまくいきません。
  • 受信処理のスレッドを作成しているが、なぜ受信できないのか理由が分かりません。
  • 質問者はrecv関数で受信した文字列を表示するために、メンバ変数に追加している。
回答を見る
  • ベストアンサー

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

今私は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 ); なぜ受信できないのか分からない状態です。 ではよろしくお願いします

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

  • ベストアンサー
  • lv4u
  • ベストアンサー率27% (1862/6715)
回答No.1

ソケットは、"ブロッキング モード" と "非ブロッキング モード" があったと思います。 現在、非ブロッキング モードになっていないのではないでしょうか? それから、詳しく覚えてはいませんが、Windowsのソケット関数の仕様は、Unixx等のソケット関数と違っていたと思います。 「ソケットの一般的な仕様はこうである。そしてスレッドの仕様はこうである。だから、動作するはずである。」 と思ってプログラムを作ると、Windowsの場合、まともに動作しない可能性があります。 なので、私は、Unix上では、ソケットのプログラムをマルチスレッドで作成しても、相手となるプログラムがWindows上で作成する場合、マルチスレッドでは、作りませんでした。 まあ、マルチスレッドにすれば、プログラムが簡単になる面はありますが、動作しなかった場合の原因究明とうまく修正する自信が無かっただけなんですが・・・。

関連するQ&A

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

    こんにちは。 私は、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関数を監視する方法があるのでしょうか? よろしくお願いします。

  • スレッドが作れない

    VC9SDKで、スレッドを作る時_beginthreadexの第3引数の型でエラーが出てしまいます。 ・・・main(・・・){ HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, &Process, NULL, 0, ID_PROCESS); } int __stdcall Process(){ } これはどう書けば解決するんでしょうか? お願いします。

  • マルチスレッドプログラム

    いつもお世話になっております。 今回はマルチスレッドプログラムについてお聞きしたいです。 マルチコアCPUを使ってたとえば下記のようなことをしたいときに for (int i = 0; i < 1000000; i++) { sum += i; } このまま計算するよりもいくつかスレッドを作って、計算量を分散させてから最後に足してやるほうが早いと思いまして、 現在Core2Quadが手元にありましたのでスレッドを4つ作って スレッド1で0から250000まで スレッド2で250001から500000まで スレッド3と4も同様にして実際にやってみたのですが スレッドなしの状態よりも倍くらい時間がかかってしまうようになってしまいました。 計算結果は同じになり、CPU使用率もシングル時が25%、マルチ時が100%になっているので意図したようにはできていると思います。 GetProcessAffinityMaskを使って、各スレッドにひとつづつコアを割り当てても同様でした。 実際に時間が4分の1に近くなると思っていたのですが2倍かかってしまったので不思議です。 どなたか上記のことを思惑通りに動かせそうな方法をご存知の方はご教授願います。 プログラムは全部は無理ですが重要そうなところは下記のとおりです。 スレッド作成部分 {   DWORD dwStart = ::timeGetTime();   _thread_handle[0] = (HANDLE)::_beginthreadex(NULL, 0, thread_first, NULL, CREATE_SUSPENDED, &_thread_first_id);   _thread_handle[1] = (HANDLE)::_beginthreadex(NULL, 0, thread_second, NULL, CREATE_SUSPENDED, &_thread_second_id);   _thread_handle[2] = (HANDLE)::_beginthreadex(NULL, 0, thread_third, NULL, CREATE_SUSPENDED, &_thread_third_id);   _thread_handle[3] = (HANDLE)::_beginthreadex(NULL, 0, thread_forth, NULL, CREATE_SUSPENDED, &_thread_forth_id);   for (int num = 0; num < 4; num++)   {     ::ResumeThread(_thread_handle[num]);   }   ::WaitForMultipleObjects(4, _thread_handle, TRUE, INFINITE);   for (num = 0; num < 4; num++)   {     ::CloseHandle(_thread_handle[num]);   }   DWORD dwEnd = ::timeGetTime(); } 各スレッド部分 { HANDLE hCurrent = ::GetCurrentProcess(); DWORD pamask, samask, patmp = 0; int nRet = ::SetProcessAffinityMask(hCurrent, 0x0001); ::GetProcessAffinityMask(hCurrent, &pamask, &samask); DWORD dwStart = ::timeGetTime(); _result1 = 0; for (int multi = 0; multi < _multi; multi++) {   for (DWORD i = 0; i < 100000/4; i++)   {     _result1 += i;   } } DWORD dwEnd = ::timeGetTime(); time1 = dwEnd - dwStart; ::_endthread(); return 0; } 開発環境は WindowsXP SP3 VisualStudio6.0 ATL/WTLです。

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

    こんばんわ。 マルチスレッドプログラミングを行なっています。開発環境はVC++.NET2003でC言語を用いてコンソールアプリケーションを勉強中です。 以下にプログラムを示します。 以下のプログラムは、 (1)ThAとThBが交互に1~10までカウントUP (2)ThBだけが11~20までカウントUP (3)ThAはTh11から、ThBは21からカウントUP というプログラムを記述したつもりなのですが・・・実行開始後は(1)から(3)のように表示できるのですが、それ以降はThAとThBが交互に表示されてしまいます。 (1)から(3)を繰り返す記述の仕方はありますでしょうか? よろしくお願い致します。 HANDLE hEvent[3]; unsigned __stdcall ThB(void *lpx){ int j; int l=1; for(j=1;j<100;j++){ Sleep(100); printf("ThB%d\n",j); if(l%20==0){ SetEvent(hEvent[0]); } l++; } return 0; } unsigned __stdcall ThA(void *lpx){ int k; int j=1; for(k=1;k<100;k++){ Sleep(100); printf("ThA%d\n",k); if(j%10==0){ WaitForSingleObject(hEvent[0],INFINITE); } j++; } SetEvent(hEvent[2]); return 0; } int main(int argc ,char *argv[]){ unsigned int thID[2]; HANDLE hTh[2]; int i; hEvent[0] = CreateEvent(NULL, TRUE, FALSE, "CH0"); hEvent[1] = CreateEvent(NULL, TRUE, FALSE, "CH1"); hEvent[2] = CreateEvent(NULL, TRUE, FALSE, "MAINEVENT"); hTh[0] = (HANDLE)_beginthreadex(NULL, 0, ThA, NULL, 0, &thID[0]); hTh[1] = (HANDLE)_beginthreadex(NULL, 0, ThB, NULL, 0, &thID[1]); WaitForSingleObject(hEvent[2], INFINITE); for(i=0;i<2;i++) CloseHandle(hTh[i]); return 0; }

  • (マルチスレッド)_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); } }

  • send-recvで複数データの送受信

    初歩的な質問で恐縮ですがよろしくお願いいたします。 send側 :WindowsVista VC6 recv側 :Linux2.6.18-at9 Debian PowerPC でunsigned longのデータ数千個を順次送受信するプログラムを組んでいるのですが不調です。 ともにBlockingモードで動作しているのだから双方にWhileループを組めば特段のHandShakeは不要で受信側所定バッファに逐次取り込めるのだと思っていました。しかし: 1.受信側ループにprintf、sleep(1)等を入れないと受からない。  なお受信側はMainとは別のスレッドにしています。 2.毎回内容ゼロのデータがもう一つ加わってしまう。  recvが毎回データ到着までBlockつまり待ちにしていると期待したのですが、2回通り抜けたような効果があり、各データにゼロデータがもう一行付加されてしまう。つまりデータ量が2倍になる。 プログラム: 送信側: SOCKET s; unsigned long dataBuf char buf[20]; int ok; while ( count < DATANO) ){  fread(&dataBuf, sizeof(dataBuf),1,fp);      // ファイルより読込み sprintf(buf, "%d", dataBuf); ok = send(s, buf, sizeof(buf), 0); // Blocking Mode ? if(ok==SOCKET_ERROR){ printf("Command送信不良"); exit(1); } count++; } 受信側: void* dataReceiveThread(void* pParam) {  char buf[10];  int recvSize, count = 0;  unsigned long val, memBuf[4096];  while(1){   memset(buf, 0, sizeof(buf));   recvSize = recv(conn_fd, buf, sizeof(buf), 0); // Blocking Mode   if(recvSize == 0){    printf("conn_fd broken by Host\n");    close(conn_fd);    break;   }   else if (recvSize == -1) {    perror("recv");    exit(EXIT_FAILURE);   } val = atol(buf); ⇒ printf("val %x\n", val);   if (count < DATANO){ memBuf[count] = val; else break; count++; } このプログラムは初回のデータは問題なく受信できます。 以降のデータは⇒でループ速度を下げないと受信できません。しかしこれは仕様に合いません。 ただしデータ量が2倍になってしまうのでFlipFlopを入れてループを間引いて強引に辻褄合わせをしたところデータはそれらしく受信できます。しかし指定回数ループできません。 recvのBlock機能を誤解しているのかもしれない考え、selectを入れるなどしたのですが解決しません。send-recvの基本仕様を理解していないためと思われます。 ご教示願えれば幸いです。

  • C++ GUIのメッセージループ。

    初心者です。 よろしくお願いします。 とても重く時間の掛かる処理を色んなサイトを参考にスレッドにしてみたんですけど、書き方が悪いのか、再描写がワンテンポ遅れたり、アプリケーションを複数起動したりするとフリーズしてしまったりします。 原因はメッセージループにあるような気がしてるんですが、この書き方はおかしいですか?? どのサイトから引用したのかわからなくなってしまいました。 気付いたことなどあったら何でもいいので教えて貰えたら嬉しいです!よろしくお願いします!! thread01に重い処理が書かれてます。 int thread_call() {   unsigned int dwThreadId[1];   HANDLE hThread[0] = (HANDLE)_beginthreadex(     NULL,     0,     ( unsigned int (__stdcall*)(void*) )thread01,     NULL,     0,     &dwThreadId[0] );   MSG msg;   DWORD dwRet = WAIT_TIMEOUT;   while ( 1 ) {     dwRet = ::MsgWaitForMultipleObjects( sL, hThread, FALSE, INFINITE, QS_ALLEVENTS );     if ( dwRet == WAIT_OBJECT_0 + sL ) {       if ( ::PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) {         ::TranslateMessage( &msg );         ::DispatchMessage( &msg );       }     } else if ( dwRet >= WAIT_OBJECT_0 && dwRet < WAIT_OBJECT_0 + sL )       break;   }   CloseHandle( hThread[0] );   hThread[0] = NULL; }

  • マルチスレッドについて・・・

    先日マルチスレッドについて質問させていただいたものですが、助言のもと動かしてうまくいったように見えたのですが、ロードしていない部分がありました。 今回はスレッドの中身もかいておきます。 ご助力お願いいたします。 unsigned int WINAPI GameMain::loadthread(void *lpx) { GameMain* gm = (GameMain*)lpx; gm->GInit();   //ロード return 0; } HRESULT GameMain::LoadScreen() { // スレッドの生成 static bool onlyonce_createthread = FALSE; if(onlyonce_createthread ==FALSE) { hTh = (HANDLE)_beginthreadex( NULL, 0, &loadthread, this, 0, (unsigned*)&thID ); onlyonce_createthread =TRUE; } // ローディング画面の描画 static bool loopflg = TRUE; while(loopflg) { int threadCondition = CheckThread( hTh ); switch(threadCondition) { case THREAD_RUNNING: if(graphloaded_flg ==TRUE) //2D画像のロードが終わったら { EnterCriticalSection( &m_criticalSection ); float keep_item = (float)(load_item/MAX_LOAD_ITEM); LeaveCriticalSection( &m_criticalSection ); d2d_control->GaugeDraw(0, 0, keep_item); //画像の描画関数 } break; case THREAD_EXIT: loopflg =FALSE; break; case THREAD_ERROR: return E_FAIL; break; } } float keep_item = (float)(load_item/MAX_LOAD_ITEM); d2d_control->GaugeDraw(0, 0, keep_item);  //画像の描画関数 return S_OK; }

  • CSocket通信での待機処理について

    VC++2008にて、サーバとクライアントPCにて、相互通信を行うプログラムを作成しています。 クライアントは、CSocketを利用しマルチスレッドにて通信を行っています。 thread_start→マルチスレッド作成→ CSocket::Sendでサーバへメッセージ送信→ CSocket::OnReceiveでサーバのメッセージ受信→ サーバメッセージから処理実行と言った流れです。 通常の処理は、この流れで問題ないのですが、 ある処理の場合、thread_startをforループで数回繰り返す 処理を行っています。 この時、データにタイムラグが出てしまうため、 thread_startから処理実行までの一連の流れが終了するまで、 次のthread_startは呼ばれずに待機させたいのですが、 どのようにすれば良いのかが分かりません。 Sendを呼んだタイミングで、 WaitForSingleObjectでスレッドのハンドルを渡したり、 CreateEventでイベントハンドルを渡したりしてみたのですが、 WaitForSingleObjectを呼ぶと、OnReceiveで受信する前で 止まってしまうため、そのままフリーズ状態になってしまいます。 どのタイミングでWaitFor~を呼ぶべきなのか、 もしくは、何か別の手段があるのでしょうか?

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

    実際のプログラムでバグが出たので、簡易化したプログラムでテストしてみましたがどこが悪いのか分かりませんでした。 #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 どこを直せばいいか教えてください

専門家に質問してみよう