• ベストアンサー

ソケットプログラミングのrecv時にFD_READイベントが終わらない

現在Winsockを用いているのですが、クライアントからのデータを受信したときにおこるFD_READイベントをWSAWaitForMultipleEventで受け取って処理しているのですが、recvからの戻り値が常に0にも関わらずFD_READイベントが発生し続けます。クライアント側での送信は成功しています。 このような事態が発生する原因としてはどのようなことが考えられますでしょうか?

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

  • ベストアンサー
  • i-kujou
  • ベストアンサー率50% (13/26)
回答No.1

正式な資料にあたったわけではないですが、recvの戻り値が0ということはコネクションが切断されているということですから、closesocketしない限りずっと「切断されている」という受信イベントが立って、FD_READが発生するのではないでしょうか?

bh5375
質問者

お礼

ご返答ありがとうございました。自己解決いたしました。 どういった状況であったかだけ説明させていただきますと、自身の作成し た送受信処理クラスにおいてrecv時のバッファサイズをメンバ変数に持た せていたのですが、その変数が「0」で初期化されていたままでした。 その変数はオーバーライドされたコンストラクタで任意の値に設定できる ようにしてあるのですが、それを行っていませんでした。つまりクラスの インスタンスが作成されていただけで安心していたわけです。 その結果、recvで受信するデータのサイズが0バイトということになって おり、受信可能データが全く減らないということになりFD_READイベント がなくなることもなく無限ループになっていたという落ちでした。 しかしrecvにこのような落とし穴というか、あくまで私自身が気づきに くいケースに遭遇できたという点で勉強になりました。

関連するQ&A

  • ソケットプログラミングとスレッドについて

    TCP/IPソケットを用いた通信プログラムを作成しています。その上でacceptする処理を専用スレッドにしており、accept後の受信処理をまた別のスレッドで処理しています。コンソールプログラムにおいてサーバとクライアントを用意しテストをしてみるとうまくいくのですが、MFCプログラムにおいて同じネットワーク処理を行ってみると、サーバ側へのconnectは成功するのですが、クライアント側からsendしたときにサーバ側でrecvの戻り値が必ず0にしかならず切断された状態になってしまいます。これはどういったときに発生すると考えられるでしょうか?ちなみにMFCが絡んでいるかどうかということは特にわかっておりません。 どなたかこのような経験をお持ちであればご教授お願い致します。

  • 非ブロッキングソケットのrecvについて

    現在、Winsock2を使ってあるサーバーのプログラムを作成しています。 WSAEventSelect関数を使って非ブロッキングソケットを扱っているのですが、複数のクライアントからほぼ同時に接続要求などがあった際に 接続を取りこぼしてしまいます。 どなたかアドバイスいただけませんでしょうか。 以下、ソースを示します。プログラムの動作をわかりやすくするためエラー処理などは省略して記載します。(実際には行っています) ちなみに非ブロッキングソケットを使用する理由は以下のとおりです。 ・GUIアプリのワーカースレッドで動作させており、ブロッキングソケットでブロック中にメインスレッドが終了してもワーカースレッドがそれを知る術がなくワーカースレッドを安全に終了させることができないため。 /* 変数の宣言*/ int iRet=-1; SOCKET ListenSock; SOCKET AcceptSock; int iRcvClientLen=0; int iRcvLen=0; char caRcvDat[1024]={0}; WSAEVENT hEvent; DWORD dwResult; WSANETWORKEVENTS events; /* リッスンソケットを作成*/ ListenSock = socket(AF_INET, SOCK_STREAM, 0); /* イベントのクリエイト*/ hEvent = WSACreateEvent(); /* リッスンソケットの設定*/ addr.sin_family = AF_INET; addr.sin_port = htons(PORT_NUM); /*PORT_NUMは定数*/ addr.sin_addr.S_un.S_addr = INADDR_ANY; /* リッスンソケットをバインド*/ iRet = bind(ListenSock, (struct sockaddr *)&addr, sizeof(addr)); /* リッスンソケットでポートを開く*/ iRet = listen(ListenSock, 10); /* クライアント接続待ちの無限ループ*/ while (1) { printf("\n\n/--------- 待機中 ---------/\n\n"); iRcvClientLen = sizeof(client); /* リッスンソケットにACCEPTイベントを設定*/ iRet = WSAEventSelect(ListenSock, hEvent, FD_ACCEPT); /* ACCEPTイベント発生まで待機*/ dwResult = WSAWaitForMultipleEvents(1, &hEvent, FALSE, WSA_INFINITE, FALSE); /* 発生したイベントを解析*/ iRet = WSAEnumNetworkEvents(ListenSock, hEvent, &events); /* イベント変数をリセット*/ WSAResetEvent(hEvent); /* 発生したイベントがACCEPTであれば接続を受け入れる*/ if(events.lNetworkEvents & FD_ACCEPT){ AcceptSock = accept(ListenSock, (struct sockaddr *)&client, &iRcvClientLen); } /* ACCEPTしたソケットにREADイベントを設定しなおす*/ iRet = WSAEventSelect(AcceptSock, hEvent, FD_READ); /* READイベント発生まで待機*/ dwResult = WSAWaitForMultipleEvents(1, &hEvent, FALSE, WSA_INFINITE, FALSE); /* 発生したイベントを解析*/ iRet = WSAEnumNetworkEvents(AcceptSock, hEvent, &events); /* イベント変数をリセット*/ WSAResetEvent(hEvent); /* 発生したイベントがREADであればデータを読み込む*/ if(events.lNetworkEvents & FD_READ){ iRcvLen=recv(AcceptSock, caRcvDat, 1024, 0); /* ・・・以下Recv後の動作・・・*/ } } おそらく、2回目のWSAWaitForMultipleEvents関数で待機している間に接続要求が来たクライアントを取りこぼしているのだと思いますが、 対処方法がわかりません。

  • ソケットのrecvの戻り値が0

    linuxにてソケットの勉強をしようと思い、 簡単なソケット通信のプログラムをCで組みました。 ret = recv(ID, Buff, sizeof(Buff), 0); といった感じでサーバ側を組んだのですが、 この戻り値retに0が入ることがあり、思うように動いてくれません。 私の認識だと、recvは受信するまで待ち、 受信したサイズを返すと思っているのですが、 それが0とは、いったいどういう意味を持つのでしょうか?

  • winsock windowprocでFD_WRITEの処理

    すみません。よくわからなくなったので教えてください。 非同期処理を行いwindowprocで送信、受信の処理をしているのですが、一部わかりません。 [内容] クライアントからデータを送信してもらい、サーバ側で受信をして、サーバ側で受信後、クライアントへ送信をしたいのですが.... [サーバ側ソース抜粋] ::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { int EventErrorCoode; int len; switch(message) { case FM_TCPPROC: EventErrorCoode = WSAGETSELECTERROR(lParam); switch(WSAGETSELECTEVENT(lParam)){ case FD_CONNECT: //コネクトされたときの処理 break; case FD_ACCEPT: if(EventErrorCoode != 0){ NetWork_LogOut(); break; } // 状態判定処理 if(NetWork_Accept() == FALSE){    //失敗したときの処理 } break; case FD_READ: // データの受信メッセージ if(NetWork_Recv() == FALSE){   } break;  case FD_WRITE: //テスト折り返し送信  SendData = "折り返し";  strcpy(Recv_Buffer,SendData);  len = send(server_s, Recv_Buffer, strlen(Recv_Buffer),0); break;    :    : return CDialog::WindowProc(message, wParam, lParam); } ::NetWork_Recv() { int nResult; int len; nResult = recv(client_s, (CHAR *)Recv_Buffer, RECV_SIZE - 1, 0); Recv_Buffer[nResult] = '\0'; return TRUE; } *非同期処理はsocket作成後しています。 クライアントから送信されたデータが、FD_READで認識し、NetWork_Recv()関数を使って受信します。 その後、空になった時点で、FD_WRITEを実行すると思っていたのですが、recvされた後、データは空にならないのでしょうか?

  • ソケットプログラミングについて

    こんにちは。 以前、この掲示板に質問させていただいた者です。 送信側から受信側へWinsockを利用し、jpeg,mpegファイルを送信したいのですが、プログラムを実行すると強制終了されてしまいます。以下に主要部分を記述します。 [送信側] FILE *fp; char fname[100]; printf("読み込み用ファイルを入力して下さい:"); scanf("%s",fname); if((fp = fopen(fname,"rb")) == NULL){ printf("入力ファイルをオープンできない。\n"); exit(1); } char send_buf[1025]; int nRet; int n; while(n = fread(send_buf,1,1024,fp) != -1){ sendto(theSocket,send_buf,n,0,(LPSOCKADDR)&saServer,sizeof(struct sockaddr)); } fclose(fp); closesocket(theSocket); [受信側] FILE *fp; char fname[100]; printf("書き込み用ファイルを入力して下さい:"); scanf("%s",fname); if((fp = fopen(fname,"wb")) == NULL){ printf("出力ファイルをオープンできない。\n"); exit(1); } char Recv_buf[1025]; char size; SOCKADDR_IN saClient; while(1){ size = recvfrom(theSocket,Recv_buf,1024,0,(LPSOCKADDR)&saClient,&nLen); fwrite(Recv_buf,size,1,fp); } fclose(fp); closesocket(theSocket); 受信側を先に起動し、送信側を起動。送信側で1024バイトずつ送信し、受信側でwhileの無限ループを用いて送信側からのデータを受信するプログラムにしたつもりです。しかし、送信側で読み込みファイルを指定すると強制終了されてしまいます。ファイルオープンの仕方がおかしいのでしょうか?また、上記のプログラムでは1024バイトずつ送信できるようになっていますでしょうか? よろしくお願いします。

  • ソケットプログラミング

    こんにちは。 ソケットプログラミングを勉強していて、音声を送りあえるIP電話らしきものを作ろうとしています。音声のやりとりは何とかできていますが、同時に文字列も送れるようにしたいです。ソケットをもう一つ作ればいいのではないかと思っていますが、実際に書いてみると、recv()の部分がうまく書けません。 音声データの送受信の部分は: while(1){ n=recv(sock,data1,N,0); //受信 if (n== -1){perror("recv");exit(1);} if(write(dsp, data1,n)==-1){perror("write"); exit(1);} //スピーカーから出力 n=read(dsp,data,N);  //マイクから入力 if (n== -1){perror("read");exit(1);} if(send(sock,data,n,0)==-1){perror("send");exit(1});} //送信 } 送信の時は n=read(0,tdata_2,N); send(sock_2,data_2,n,0); のように標準入力から文字列を読み込んで、data_2に格納し、新しく作ったソケットsock_2で送ればいいのですが、受信の時はどうしたらいいでしょうか。recv()をつかって、文字列と音声のデータを違うソケットで受け取って、違う配列に格納する方法があるでしょうか。 つまり、このような感じ(?): n1=recv(sock1,data1,N,0); //音声 n2=recv(sock2,data2,N,0); //文字列 とても悩んでますので、よろしくお願いします!!

  • ソケットプログラミングに関する質問です

    ソケットプログラミングに関する質問です 最近ソケットプログラムに興味があり、勉強をしているのですが、 手始めにと下記の2つのプログラムをそのまま記述し http://cs.baylor.edu/~donahoo/practical/CSockets/code/TCPEchoClient.c http://cs.baylor.edu/~donahoo/practical/CSockets/code/TCPEchoServer.c TCPEchoClientプログラムから送信した英数字をTCPEchoServerがキャッチして TCPEchoClientの方へ送り返すプログラムを作ってみました。 その後、応用として手始めにTCPEchoClient側の送信元IPアドレスと送信した文字列 ex: 192.xxx.xxx.xx 'Hello World!' を送り返すプログラムを作成するために、 同じサイト内にあったHandleTCPClientを下記の通り 改造してみたのですが、引数に問題があるとエラーが出て先へ進めません。>< #include<stdio.h> #include<sys/socket.h> #include<unistd.h> #define RCVBUFSIZE 256 /* 受信バッファのサイズ */ void DieWithError(char *errorMessage); /* エラー処理関数 */ void HandleTCPClient(int clntSocket, int echoClntAddr) /* TCPクライアント関数処理 */ { char echoBuffer[RCVBUFSIZE]; /* エコー文字列のバッファ */ int recvMsgSize; /* 受信メッセージのサイズ */ struct clintIP echoClntAddr; /* クライアントのIPを取得 */ /* クライアントからの受信メッセージ */ if ((recvMsgSize = recv(clntSocket, echoBuffer, RCVBUFSIZE,clintIP,0)) < 0) DieWithError("recv() failed"); /* 受信した文字列を送信し、転送が終了していなければ次を受信する */ while (recvMsgSize > 0) /* 0は転送の終了を意味する */ { /* メッセージをクライアントにエコーバックする */ if (send(clntSocket,echoBuffer,recvMsgSize, 0) != recvMsgSize) DieWithError("send() failed"); /* 受信するデータが残っていないか確認する。 */ if ((recvMsgSize = recv(clntSocket, echoBuffer,RCVBUFSIZE, 0)) < 0) DieWithError("recv() failed"); } close(clntSocket); /* クライアントソケットをクローズする */ } 単純にTCPEchoServerの echoClntAddr.sin_addrという箇所が送信元のIPを 引っ張ってきてるからHandleTCPClientの方へ 関数をstructで引っ張ってくればいいと思ったのですが、そういうわけでもないのです。

  • recv関数の戻り値について

    おせわになります。 socket関数(WinSock2)のrecv関数のことで質問なのですが、 第4引数にMSG_PEEKを指定したときと、指定しない時(=0) の戻り値が、明らかに違うのです。 実際は、20000バイトを送信し、受信側でrecvすると、 MSG_PEEKを指定すると、8760が返り、 MSG_PEEKを指定しない(=0)と、20000が返ります。 (もっと試して、200000と10倍にしても一回で受信しました。) recvが一度に受信できる容量のテストをしていたときに発見したのですが、こういうものなのでしょうか? 以上、よろしくおねがいします。

  • Socket通信で、通信終了のイベントが発生しない

    クライアント(Windows)とサーバ(Unix)とSocket通信をするアプリを作っています。処理内容はクライアントのデータファイルをサーバに送信(アップデイト)し、サーバ側でデータを解析し、その結果を印刷するという手順です。 WinSockを使って、送信そのものはうまくいくのですが、サーバでデータを解析し結果を印刷するのに時間がかかり(10秒以上)、その間は送信終了のイベントが発生しません。これはサーバ側での処理を exec関数とwait関数で行っているので、正しい事態なのですが、データの送信が終わったら後はサーバ側で勝手にやって欲しいのです。サーバでの処理を system関数に置換えたり、バックグランド処理にしてもやはり処理が終わるまで送信終了のイベントが発生しません。何かいい方法をお教えください。

  • winsock2 非同期処理について

    教えてください。 winsockを使用して、ネットワーク間のアプリを作成しているのですが、 wndPorcが処理されないため困っています。 お分かりになる方教えてくださいませ。 送信側はメッセージを送っていますが、受信側のaccept処理が出来ません。(wndProcが呼ばれない) wndPorc関数って呼び出しって必要でしたか??? [環境] OS windows2000 Visual C++ 6.0 MFC [ソース] [.cpp内部] bool CSysCp02Dlg::NetWork_LogOn() { struct sockaddr_in server; // winsock初期処理 // ソケット作成 // 非同期処理 if(WSAAsyncSelect(server_s,this->m_hWnd,FM_TCPPROC,FD_ACCEPT|FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE) == SOCKET_ERROR){  return false; } // 構造体をクリア // 設定 // bind処理 // 受付開始(listen処理) return true; } LRESULT CALLBACK CSysCp02Dlg::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) <----ここの関数が処理されない。 { struct sockaddr_in client; int n; char Recv_Buffer[RECV_SIZE]; int nLength = sizeof(client); switch(message) { case FM_TCPPROC: switch( lParam ){ case FD_ACCEPT: client_s = accept(server_s, (struct sockaddr *)&client, &nLength); if(client_s == INVALID_SOCKET){ ErrNum = WSAGetLastError(); } break; } } return WndProc(hWnd, message, wParam, lParam); } 800文字以内に入りきらないため、略してあります。

専門家に質問してみよう