• ベストアンサー

非同期関数とノンブロッキング関数について(winsock)

こんばんわ。 VC++.NETにてコンソール上でソケットプログラミングをしています。 非同期モードとノンブロッキング関数について知りたいのですが、私は、今までTCPやUDPでsendtoやsend関数を使用してきました。しかし、非同期やノンブロッキング関数があることを知り、詳しく知りたいと思っています。 1.非同期やノンブロッキング関数はGUI作成を行う上では重要であるが、コンソール上でプログラミングを行っている場合は利用しなくてよいのでしょうか? 2.以下のWSAAsyncSelect関数の第2引数の設定がわかりません。サンプルでは、hwndに関連付けられたウィンドウがSM_EVENTメッセージを受け取りますと記述されていますが、ウィンドウを利用していないコンソールアプリでの記述方法はありますでしょうか? HWND hwnd; WSAAsyncSelect(Sock,hwnd,SM_EVENT,FD_WRITE); と記述し実行した場合、強制終了されてしまいます。 3.たとえば、送信側から送信したパケットを受信側で受信し、再度受信側から送信側へ送信する場合を考えると、 送信側で送信と受信が必要です。この場合、マルチスレッド処理が必要だと思うのですが、非同期のFD_WRITEとFD_READを使うことで、シングルスレッドで実現可能でしょうか? よろしくお願い致します。

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

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

>>送信側で送信と受信が必要です。この場合、マルチスレッド処理が必要だと思うのですが、非同期のFD_WRITEとFD_READを使うことで、シングルスレッドで実現可能でしょうか? .NETは使ったことないのですが、以前Windowsのソケットプログラムを作るとき調べたら、「Windowsでは、Socketをマルチスレッドで使えない。ライブラリでグローバルに取られている変数があるから」って記載のある文献を目にしました。 .Netでは違うかもしれませんが・・・。 また、No.1の方の回答にあるように、Selectを使えば、送受信のデータ状況がわかるため、マルチスレッドにする必要はないです。というか、マルチスレッドにするとSelectが正常動作しないのでは? 補足ですが、socket関連の文献ってちょっと少なめで、しかもコードは「お勉強用」っていうものが多い気がします。まあ、勉強のコードに異常対応をきちんと入れたら、本筋が見えなくなる気もします。でも、socket関連の処理って異常処理が当たり前のように発生しますので、実用に耐えるレベルのコードは、「全てのエラーに完全対応する」っていうつもりで、状態遷移図を完成させてからコードを作成されるといいと思います。

bird0214
質問者

お礼

返信ありがとうございます。 socketの文献って少ないですね・・・とくにwindowsソケットは。 もともと、UNIX?で開発されてきたから仕方ないのでしょうか・・ ありがとうございました。

その他の回答 (2)

  • rinkun
  • ベストアンサー率44% (706/1571)
回答No.3

コンソールアプリケーションならselectを使えば良いかと。これならUNIXでも使える標準的な関数だしWinSockでも使えるでしょう。非同期もノンブロッキングもなしに通信の多重化ができます。 Windowハンドルを要求するAPIをコンソールアプリケーションで使うのは適切とは考えられません。

bird0214
質問者

お礼

返信ありがとうございます。 select関数を用いることで、送信スレッドおよび受信スレッドのマルチスレッド化をしなくても、シングルスレッドで送信受信が可能であるのですね。 参考にさせていただきます。 ありがとうございました。

  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.1

>1.非同期やノンブロッキング関数はコンソール上で利用しなくてよいのでしょうか? >2.ウィンドウを利用していないコンソールアプリでの記述方法はありますでしょうか? WSAAsyncSelectを使う場合は必ずウインドウハンドルが必要です。 コンソールアプリであってもCreateWindow等を使って非表示のウインドウでも作れば不可能ではありませんが メインループ及びWndProcが必要になります。WndProcがないとイベントを検知できませんから。 ただコンソールアプリの場合、別スレッドをたててWSAEventSelect等を使う方が普通だと思います。 >3.非同期のFD_WRITEとFD_READを使うことで、シングルスレッドで実現可能でしょうか? 可能です。というかWSAAsyncSelectを使う場合、別スレッドは不要です。

bird0214
質問者

お礼

返信ありがとうございます。 お返事が遅れまして、大変申し訳ありません。 ありがとうございました。

関連するQ&A

  • winsockの非同期処理について

    winsockで双方向通信のため、非同期処理を行っているのですが、うまくいきません。 クライアント側で、WSAAsyncSelectの処理の後、Connectを呼んでいるのですが、Connectでエラーメッセージを返します。(エラーナンバー: 10035) サーバ側はaccept処理はうまくいっているのですが、accept後うまく処理を返していないためだと思うのですが... で質問は、 1.クライアント側、サーバ側にそれぞれ、WSAAsyncSelect を記載しても問題ないか? クライアント側はConnect前で宣言。 サーバ側はbind前で宣言しています。 2.エラー番号10035は非ブロッキングモードで処理されないためにおきています。 Connectで非ブロッキングモード処理がされていないためだと思うのですが、他に記述しないといけない関数があるのでしょうか? クライアント側: // 非同期処理 if(WSAAsyncSelect(client_s,this->m_hWnd, FM_TCPPROC, FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE) == SOCKET_ERROR){ return FALSE; } // コネクト処理 memset(&client,0,sizeof(client)); client.sin_family = AF_INET; client.sin_addr.s_addr = inet_addr(IpAddress); client.sin_port = htons(PORT_NO); if(connect(client_s, (LPSOCKADDR)&client, sizeof(client)) == SOCKET_ERROR){ <-- ここでエラー long ErrNum = WSAGetLastError(); <-- ここでエラーNoがかえる。 return FALSE; }else{ NetFlg = true; } お分かりになる方教えてくださいませ。よろしくお願いします。

  • 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文字以内に入りきらないため、略してあります。

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

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

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

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

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

    簡単なソケットプログラムを作ろうとしておりまして、サイトで調べたりしておりましたところ、なんとか分かってきたのですが、ひとつどうしてもわからないことがありますので教えていただけますでしょうか。 ソケットから受信するメッセージの生成のところなんですが、 「WSAAsyncSelect(m_socket,m_hWnd,WM_USER_ASYNC_SELECT,FD_READ | FD_WRITE)」 で、2番目の引数「m_hWnd」がわかりません。 教えていただけないでしょうか?よろしくお願いします。

  • TCPでの非同期型select関数について

    マッキントッシュOS-X上で動くTCP通信プログラムを作る場合について教えてください。 ウィンドウアプリを考えています。 ウィンドウ環境なので、アプリがフリーズしてしまわないために、 以下のような非同期処理が考えられます。 この場合、データが来ていなくても、while(1)がぐるぐる回るので 無駄にプロセスを食ってしまうと思うのですが、これはしかたのないことでしょうか。 もっとよい方法がるのでしょうか。 Winsockだとイベント応答関数での受信処理処理ができてエレガントなのですが、 バークレイソケットでは、どうすべきなのか疑問に思い質問させていただきました。 よろしくお願いします。 //ソケットを非同期モードにセット val = 1; ioctl(sock, FIONBIO, &val); while (1) {   memcpy(&fds, &readfds, sizeof(fd_set));   select(2, &fds, NULL, NULL, NULL);   // sockに読み込み可能データが届いている場合は、受信   if (FD_ISSET(sock, &fds)) {     memset(buf, 0, sizeof(buf));     recv(sock, buf, sizeof(buf), 0);   }   else{     //受信データがなかったときの処理   } }

  • 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を使った通信での同時接続について

    WSAAsyncSelectを使ってソケットにくるネットワークイベントを受け取って処理しようとしています。 サーバーに複数のクライアントが接続してくる通信プログラムを作っています。 クライアントがバラバラのタイミングで接続してくると問題なく通信が行えるのですが 同時に接続してくると通信がうまく行えなくなってしまいます。 サーバー側で接続してくるクライアント分だけソケット作る必要がありますか? lまた、listen関数を使って無いのですが使う必要はありますか?

  • 文字列操作について(winsockの関数を用いています)

    こんばんは。 Winsockを用いてネットワークプログラミングを行っています。 A→Bへパケットを送信し、B側にてinet_ntoa関数(IPアドレスを文字列として表示させる関数)を用いて、以下のif文の条件を記述したのですが、if文内の条件がうまく動作しません。 デバッガを使用し、IPaddr内を見てみたところ、フフフフフフフフ……と言う文字列?が入っている状態です。 IPaddrに例えば、192.168.100.50等のIPアドレスを格納可能でしょうか? IPaddr[256] strcpy(IPaddr,inet_ntoa(from.sin_addr)); if(IPaddr == inet_ntoa(from.sin_addr)){  //別関数へ } よろしくお願い致します。

  • 抜け落ちている番号を取得する方法(Winsock利用)

    こんにちは。 A→Bというように、 送信端末Aから受信端末Bへパケットを送信する際に、sprintf関数を用いて、各送信パケットに対してナンバリングを行っています。 そして、受信端末において取得することができた番号と抜け落ちている番号を取得したいと思っています。 以下に、プログラムの概要を示します。 [送信側] char send_Buff[1500]; int sequence_Num = 0; //シーケンス番号のカウントアップ sequence_Num++; //sprintf関数にて、文字列格納 sprintf(send_Buff,"%d\0",sequence_Num); sendto関数を使用し、送信 [受信側] recv_Buf[1500]; int x; unsigned int count = 0; recvfrom関数にて送信端末からのパケットを受信し、recv_Bufに格納 count++; //recv_Bufの先頭要素からナル文字までを走査し、ナル文字をみつけたらナル文字の手前の要素までをreceive_seq_Numに格納 for(x=0;recv_Buf[x]!='\0';x++){  receive_seq_Num[count][x] = recv_Buf[x]; } 上記プログラムのように、記述したのですが・・・ [分からない点] 受信側にて、受信することができた各パケットのシーケンス番号のみを配列内に格納したいのですが、上記の記述方法で可能でしょうか? また、配列内に格納したシーケンス番号から抜け落ちているシーケンス番号を割り出したいのですが、どのような記述方法がありますでしょうか? 受信シーケンス番号;1,2,3,4,5,7,10,11,20,21,22・・・ 抜け落ちているシーケンス番号:6,8,9,12,13,14,15,16,17,18,19 ということです。 よろしくお願いします。