• ベストアンサー

winsock のrecvデータの終わりを知るには

Winsockの非同期プログラムで サーバーからクライアントへ,100MB前後のデータを送るプログラムを書いています. サーバーでsend()して,クライアントのcase FD_READ のイベント応答としてrecv()を繰り返すプログラムです. サイズが大きいので何度もrecev()して,データを結合していくことになりますが, 送信データの最後を知るエレガントな方法がないかと思っています. すべてが送り終わったら空send()をして,ゼロサイズのデータを送ることができればよいのですが. よろしくお願いします.

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

  • ベストアンサー
回答No.1

データサイズを送るのが確実です。 一方が一つのデータを送るだけであれば送り終わったらshutdownすることでデータの終了を通知できますが, そうでないならばデータサイズを送る以外の方法はありません。 # 100MBとのことなので,TCPのみを想定しています。

ycuhakecha
質問者

お礼

そういう情報ありがたいです。 考え方が参考になります。 受信側で、データサイズとデータ本体を分離する コードが必要となりますが、確実な方法でしょうね。

関連するQ&A

  • 延々と受信し続ける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"を受信し続けます。 どこがおかしいのか分からないので教えてください

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

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

  • 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について

    winsock、非同期モードでTCP/IP通信を行うようなプログラムを作成しています。 通常の同期モードでのプログラムは完成させることができました。 そこで、クライアント側を非同期モードにし、受信バッファにデータが入ったら受信するというようなプログラムにしたのですが、どうもうまく動作してくれません。 やはりサーバー側も非同期モードにしなければならないのですか?? どなたかご教授お願いします。

  • socket: recvはいつ,どれだけ受け取るのか?

     現在,参考書にしたがってC++でソケットプログラミングを書いています.  sendとrecvを非同期にするために,本では select関数やWSAAsyncSelect関数などを利用していて,実際,本のとおりに書いて上手く動いています.  ここで伺いたいのですが,recvは,どうやって「データが届いたか」を知るのでしょうか.  同期ならば,トランシーバでの会話のように送信側が「どうぞ」といって送受信を交代させることができますが,非同期ならばそれができません.  NICとかが,プログラムに「届いたぞ!( or これから届くぞ!)」と教えてくれるのでしょうか.あるいは逆に,プログラムがNICに「届いてる?」と聞いているのでしょうか.仮に,ここに書いたような方法で届いたことが分かったとしても,どれくらい受け取ればいいかは分かりません(それも併せて教えてもらっているのでしょうか.データを送るときには,どれだけ送ればいいか分かりますよね.受信するときはどうしてるのかを知りたいと思っています).

  • C++のWinsockでサーバーを立てて、 Javaで接続してデータを

    C++のWinsockでサーバーを立てて、 Javaで接続してデータをやりとりするプログラムを作っています。 Javaではout.printlnでサーバーに送信ができると調べたのですが、C側でどうやってうけとればいいのでしょうか? recvだと送ってもうけとりませんでした…。

    • ベストアンサー
    • Java
  • VC++2008Expressでwin32appとwinsockの勉強

    VC++2008Expressでwin32appとwinsockの勉強の為にネットワークゲームを作ろうと思ってます。 winsockについて色々調べているうちに、疑問がわいたので質問します。 実現したいのは、サーバーとクライアントが1:Nのネットワークゲームです。 プレイヤーはサーバーに接続し、部屋に入ります。 誰かが初めて部屋に入ったら、サーバー側で部屋を用意します。(複数の部屋が立つこともあります) サーバー側で用意された部屋は、タイマーのイベントで部屋の状況データが変ります。 また、部屋にいるプレイヤーがアクションを起こす度に、サーバーの状況データが変ります。 その状況データを部屋に居る1人以上のプレイヤーで参照し共有します。 またプレイヤーデータはサーバー側で全部を一括管理します。 このような、プログラムを作りたいと思ってるんですが、 例えばサーバー側でwinsockは待ちうけ(accept)の所でプログラムは止まってしまいますよね。 クライアント側では受信(recv)の所で止まりますよね。 サーバー側やクライアント側で通信を待ち受けながら、 タイマーやマウスクリックに対するイベント処理を同時に行うことは可能なんでしょうか。 出来るとしたら、どのような仕組みにする必要があるでしょうか。 よろしくお願いします。m(_ _)m

  • winsockの非同期通信のsendイベント

    winsockの非同期通信で、 case FD_WRITE: にsend()関数を書いて送信させるのはごく普通のやりかたですね。 このイベントは、 接続直後と、送信バッファが一杯だった状態から送信が可能な状態に復帰したときに 呼ばれますよね。 これだと、ユーザーが好きなタイミングで、データを送信しようと思った時に送信できません。 でも100MBなんて大きなデータを送ると、送信バッファが溢れるので、 case FD_WRITE: にsend()を書きたい。 こういうとき、どのようにコードを書くのが、よろしいのでしょうか。

  • winsock recvでデータの取得方法

    sendで送られてきたデータをrecvで取得しています。 recvで取得したあと'\0'を入れないと文字化けを起こしてしまうので'\0'を入れているのですが、そうすると送信したバイト数と違ってきます。 同じバイト数にしたいのですが、いろいろ試しましたが、うまくいきません。  ご存知の方いらっしゃいましたら、教えてください。 また、recvで受けるときは、バイト数が多くなるのは、仕方がないのでしょうか? // ------------------ ソース -------------------- DWORD byteResult; ofstream fileWrite; byteResult = 0; while(byteResult < 最大バイト数){ nResult = recv(client_s, (CHAR *)pbuff, 7000, 0); <-- 一括で最大バイト数で受信をしたいのだが、途中で文字化けを起こすので、7000バイトに区切って受信。 pbuff[nResult + 1] = '\0'; try{ fileWrite.open("D:\\suzuki\\LogOutTest\\outdir.txt", ios::app); fileWrite << pbuff; fileWrite.close(); }catch(CException e){ fileWrite.close(); return -1; } byteResult += nResult; } delete[] pbuff; よろしくお願いします。

  • WinSockのクライアント処理

    WinSockについてお尋ねしたいのですが、 クライアントからのサーバへ1頁分のデータを要求しそれを画面に表示する プログラムを作成していますが、 一ページ分の要求毎に、以下の一連の処理を行っています。 WSAStartup socket connect send recv closesocket WSACleanup この為か、netstrtで確認すると"TIME_WAIT"が多数発生しポートが あふれてしまう事があります。 そこで、私は、 WSAStartupとWSACleanup を、クライアント起動時に行う。 (いろいろ調べると、これは絶対修正すべきという事がわかりました。) もうひとつ、 "TIME_WAIT"への対処として、 socket connect も、クライアント起動時に行う事を考えています。 私の考えは適切なのでしょうか? "TIME_WAIT"への一般的な対処などお教えください。 宜しくお願いいたします。

専門家に質問してみよう