UDP通信での受信方法について

このQ&Aのポイント
  • UDP通信での受信方法について知りたいです。MFCでUDPプロトコルを使ったサーバー・クライアントをソケットプログラムで書いています。
  • クライアントから送信された文字列のコマンドをサーバで処理するために、サーバー側での受信方法としてWSAAsyncSelect()関数とrecvfrom()関数を使っています。
  • 複数のクライアントから同時にコマンドが送信された場合、それをすべて正確に受信できるのか、また他の受信方法はあるのか知りたいです。
回答を見る
  • ベストアンサー

UDP通信での受信方法について

MFCでUDPプロトコルを使ったサーバー・クライアントをソケットプログラムで書いております。 ソフトの内容は、クライアントから送信されたの文字列のコマンドをサーバで処理をするだけです。 サーバー側での受信の仕方は WSAAsyncSelect()関数を使ってソケットイベントが発生するごとに親ウィンドウに自作のメッセージ(WM_MY_MSG)が送られるように設定する ↓ WM_MY_MSGのメッセージハンドラ内でrecvfrom()関数を使って受信する。 という方法を用いています。クライアント2台ぐらいであれば正常に動きます。 質問1: まだ試したことはないのですが(というより試す環境がない)、ほぼ同時ぐらいに複数(10台ぐらい)のクライアントからコマンドが送信された場合、それを全部正確に受信できるものなのでしょうか?要するに一つのコマンドを処理中に別のコマンドが送られてきた場合の動作はどうなるのでしょうか? 質問2: UDP通信での受信をする場合の何かもっとスタンダードな方法があるのでしょうか? よろしくお願いします。

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

  • ベストアンサー
  • rasuxo
  • ベストアンサー率66% (6/9)
回答No.1

普段はMFCのSocketではなく Winsockを使っていますが基本は同じだと思いますので参考までにコメント致します。 質問1: 同時に複数のクライアントからUDPパケットが送信された場合、 データはまず受信側のSocketのキューに格納されます。 なので1つのコマンドを処理中に別の(次の)コマンドを受信しても問題ありません。キューに格納されます。 シーケンシャルにキュー内からコマンドを取り出し終えるまで同じ処理を続ければ良いかと。 質問2: MFCのSocketは古いVersionのSocketで、 困った記憶があります。v1.1? (最新情報ではないかもです) Winsockに関する良い書籍が出てますので そちらを直接利用されてはどうでしょうか? http://bookweb.kinokuniya.co.jp/htm/4797306882.html UDPはコネクションレスですし、難しいことはないと思います。

参考URL:
http://bookweb.kinokuniya.co.jp/htm/4797306882.html
_comcom
質問者

お礼

返信送れてすいません。 どうもありがとうございます。 キューに格納されるなら問題なさそうですね。 見通しが立ちました。

関連するQ&A

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

    ソケットプログラミングでの質問です. 初心者です. UDPクライアントで sock = socket(PF_INET,SOCK_DGRAM,0) でUDPソケットを生成した後に bind()なしで,UDPサーバ宛にsendto() を行った場合, サーバのrecvfrom()でクライアントの IPアドレスとポート番号が受け取ることができると思いますが ここでのIPアドレスはクライアントのアドレスで, ポート番号は他のクライアントの他ソケットが使用していないポート番号 が受け取ることができると考えてよろしいですか? クライアントのsendto()で自動的にポート番号が割り当てられるが, クライアントが,どのポートから送信したのかを知る方法はないですか?

  • WinsockによるUDP通信にて

    WinsockでUDP通信を行うプログラムを作っているのですが、 原因不明の問題が発生していて困っています。 通信手順は以下のとおりです。 (1) クライアントからサーバへ要求パケット送信 (2) 要求パケットを受け取ったサーバは、クライアントへACKを送信 (3) サーバが要求に対する応答パケットをクライアントへ送信 (4) 応答パケットを受け取ったクライアントは、サーバへACKを送信 クライアント-サーバ間でやりとりするデータは最大で992バイト、 それ以上になる場合は、分割して送信します。 パケットの分割が発生しない場合は、(1)~(3)がパケットの損失もなく通信できるのですが、 パケットの分割が発生する場合には、2回目以降の(4)のパケットがクライアントに届きません。再現率は今のところ100%です。 クライアント側のselect関数でもソケットを検出しません。 たしかにUDPは信頼性が低いですが、パケット分割が発生しないパターンでは100%届くので、UDPの仕様とは関係ないような気がします。 原因がさっぱりわからないので、アドバイスをお願いいたします。 ちなみに、クライアント、サーバともに同一端末内にあります(双方がループバックアドレスに対してパケットを送信)が、 これはテスト段階だからであって、本来はそれぞれ別々の端末で動作します。

  • UDPの接続って?

    Linuxとgccでプログラムしているのですが、 UDPによるデータ送受信で悩んでいます。 (すいません、前回も同じようなこと言いましたね(^^;) TCPであれば、サーバ側は 1.ソケット生成 2.バインド クライアント側は 1.ソケット生成 2.コネクト で通信路が確立されますよね。 UDPはどうなるんでしょうか。コネクションを張らないということは、サーバとクライアントは区別しないんですか? 今現在、TCPのプログラムのSOCK_STREAMとIPROTO_TCPの部分だけをUDPにして実行しているのですが、UDPのくせに Connectとかやってて気分が良くないのです・・・。(笑) 現在は、SetupForClient(サーバ側)とConnectToServer(クライアント側)というTCPの接続関数をそのまま使っています。前者はいいのですが、後者は明らかにUDP向けではないですよね。 もし、クライアント側の例があったら、教えていただければ嬉しく思います。

  • winsockを使った通信での同時接続について

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

  • UDPについて

    こんばんは。 UDPについてうまく理解できず困っております。 お分かりになる方がいらっしゃいましたら、教えて下さい。 わからないのはUDPでのクライアント-サーバ間での通信方法です。 例えばこちらからあるコマンドを投げたとして、向こうから結果が返ってくるとします。 UDPなのでこちらからはじゃんじゃん投げます。 サーバからもじゃんじゃん返ってきます。 でも投げるコマンドによって処理時間が違うので 返ってくるデータの順番がバラバラになってしまう可能性があると思うのです。 TCPだとコネクションはって1対1というイメージがあるのですが、 UDPはやりたい放題(?)というイメージがあります。 順番がバラバラになってしまうのはもうどうしようもないことなのでしょうか? それともプログラミングのテクニック(?)で解消できるものなのでしょうか? 1コマンド1Threadにして管理すれば良いのでしょうか? (こうすると、このコマンドに対しての結果はこれって識別できますよね???) 一人ではどうにも前に進めないので、ご指導宜しくお願いします。 意味不明な部分は補足させていただきます。

  • UDP通信について

    前回のことでかなり言われたので改変版を見てもらいたいと思います。 TCPと伝えていましたが今回、UDPに変えました。 ヘッダーはこのようになっております。 ==wsock.h== #include <Windows.h> #include <stdio.h> #pragma comment(lib,"WSock32.lib") #define PORT_NO 8000 ポート番号 #define SERVER_NAME "" enum MINE{ NONE, SERVER, CLIENT }; ソケット通信 class WSOCK{ private: WSADATA wsaData; SOCKET s; SOCKADDR_IN saddr; int rtn; int state; MINE mineFlg; char szStr[256]; エラーメッセージ用 u_short port; 変換後のポート番号 int fromlen; 受信したサイズ HOSTENT *lpHost; ホスト情報 ファイルディスクプリタをまとめた構造体 //→ソケット判別する為の管理情報 fd_set fds,readfds; public: char szRcvBuf[1024]; 受信バッファ char szSndBuf[1024]; 送信バッファ SOCKADDR_IN from; ソケットアドレス構造体 WSOCK(); ~WSOCK(); bool ServerRcv(); 受信 bool ServerSnd();送信 bool CliantRcv();受信 bool CliantSnd();送信 void SarverSet(); void ClientSet(); bool EnumMyIPAddress(); }; ==wsock.cpp== #include "wsock.h" コンストラクタ WSOCK::WSOCK(){ //WinSock初期化 rtn = WSAStartup(MAKEWORD(2,2),&wsaData); if(rtn != 0){ MessageBox(NULL,"WSAStartup失敗", "ERROR",MB_OK); state = -1; } ソケットを開く s = socket(AF_INET,SOCK_DGRAM,0); if(s<0){ MessageBox(NULL,"ソケットをオープンできません", "eRROR",MB_OK); WSACleanup(); state = 2; } 0で初期化 memset(&saddr,0,sizeof(SOCKADDR_IN)); saddr.sin_family = AF_INET;//アドレスファミリー saddr.sin_port = htons(PORT_NO);//ポート mineFlg = SERVER; サーバ側設定 if(mineFlg == SERVER) { SarverSet(); } if(mineFlg == CLIENT) {クライアント ClientSet(); } } WSOCK::~WSOCK(){ closesocket(s); ソケットのリソース解放 rtn = WSACleanup(); if(rtn == SOCKET_ERROR){ MessageBox(NULL,"WSACleanup失敗","ERrOR",MB_OK); state = -2; } } //受信 bool WSOCK::ServerRcv(){ 読み込み用fd_setの初期化 selectが毎回内容を上書きしてしまうので毎回初期化 memcpy(&fds,&readfds,sizeof(fd_set)); struct timeval timeout = {0,0};   //{1秒以上の部分()s、1秒以下の部分(ms)} fdsに設定されたソケットが読み込み可能になるまで待つ select(0,&fds,NULL,NULL,&timeout); ソケット読み込み可能データがある場合 if(FD_ISSET(s,&fds)){ fromlen = (int)sizeof(from); //nullで初期化 memset(szRcvBuf,'\0',sizeof(szRcvBuf)); //受信処理 rtn = recvfrom(s,szRcvBuf,(int)sizeof(szRcvBuf)-1,0, (SOCKADDR*)&from,&fromlen); if(rtn == SOCKET_ERROR){ MessageBox(NULL,"recvfromエラー","ERRoR",MB_OK); return false; } } szRcvBuf[rtn] | '\0';//NULLコード if(strcmp(szRcvBuf,"c_end") == 0){ MessageBox(NULL,"クライアントが接続を切りました","ERROr",MB_OK); return false; } return true; } 送信 bool WSOCK::ServerSnd(){ char buf[1024]; memset(buf,0,sizeof(buf)); //_snprintf:書式指定文字付きデータ書き込み _snprintf(buf,sizeof(buf),"data to port 8000"); //送信処理 rtn = sendto(s,szSndBuf,(int)strlen(szSndBuf)+1, 0,(LPSOCKADDR)&from, 送り先サーバ/クライアント sizeof(from)); サイズ if(rtn != (int)strlen(szSndBuf)+1){ MessageBox(NULL,"sendtoエラー","サーバーエラ",MB_OK); closesocket(s); WSACleanup(); return false; } return true; } 受信 bool WSOCK::CliantRcv(){ fromlen = (int)sizeof(from); //nullで初期化 memset(szRcvBuf,'\0',sizeof(szRcvBuf)); //受信処理 rtn = recvfrom(s,szRcvBuf,(int)sizeof(szRcvBuf)-1,0, (SOCKADDR*)&from,&fromlen); if(rtn == SOCKET_ERROR){ MessageBox(NULL,"recvfromエラー","ERRoR",MB_OK); return false; } szRcvBuf[rtn] | '\0'; //NULLコード if(strcmp(szRcvBuf,"s_end") == 0){ MessageBox(NULL,"接続を切りました","ERROr",MB_OK); return false; } return true; } 送信 bool WSOCK::CliantSnd(){ 送信処理 rtn = sendto(s,szSndBuf,(int)strlen(szSndBuf)+1, 0,(LPSOCKADDR)&saddr, 送り先サーバ/クライアント sizeof(saddr)); サイズ if(rtn != (int)strlen(szSndBuf)+1){ MessageBox(NULL,"sendtoエラー","erROR",MB_OK); closesocket(s); WSACleanup(); return false; } return true; } void WSOCK::SarverSet(){ saddr.sin_addr.s_addr = htonl(INADDR_ANY); ソケットにローカルアドレスを関連付ける if(bind(s,(LPSOCKADDR)&saddr, (int)sizeof(saddr)) == SOCKET_ERROR){ MessageBox(NULL,"bindエラー","er",MB_OK); closesocket(s); WSACleanup(); state = -3; } FD_ZERO(&readfds); FD_SET(s,&readfds); } void WSOCK::ClientSet(){    クライアント側設定    ホスト名からホスト情報を取得 lpHost = gethostbyname(SERVER_NAME); サーバのアドレスをセット memcpy(&(saddr.sin_addr), lpHost->h_addr_list[0], //サーバのアドレス lpHost->h_length); } となっております。

  • UDP通信におけるbind関数について

    初めて質問させていただきます。よろしくお願いします。 最近、ネットワークプログラミングの勉強をしているのですが、bindについてよくわからなくなってきました・・・。よろしければご教授願います。 質問内容は以下の通りです。 (1)bindにおける設定内容は、「相手側のIPとポート番号」なのか「自分側のIPとポート番号」なのか?  色々なところを調べてみましたが、「IPとポート番号」を設定する、としかかかれてなく、いったいどっちなのかがわからなくなってきました・・・。 (2)UDP通信において、bindは必要なのか?  サーバ-クライアントの関係が曖昧なUDP通信において、bindというのは必要なのでしょうか。 私の認識では例えば、「recv関数」などを使い受信待ちをする場合はbindが必要だが、送信だけの場合には不要であるとなっています。 この認識はあっているのでしょうか。 拙文ですが、どうか教えていただきたく <(_ _*)>

  • UDP受信時の通信異常検知について

    お世話になります。 UDPマルチキャストを勉強しているのですが、 recvfrom()で受信を待っている間にifdownなどでネットワーク断が 発生した場合、一般的にどうやってそれを検知するのでしょう? tcpdumpではifdownを打つと同時にNetwork is down.と表示された ので、なんらかの方法で検知できるとは思うのですが、、、 どなたかご存じでしたらご教授ください。

  • UDP/IPでのソケット作成について(winsock)

    UDP/IPでのソケット作成について(winsock) 開発環境VC++.NET、O/S WIN2000にてソケットプログラミング(winsock2.0)をしています。 コンソールプログラミングではありませんが、WindProcは持っていません。 UDPサーバーを作り、複数クライアントの対応をしたいと考えています。 クライアントAからの通信やりとり中に クライアントBからの通信がきたら、そちらとも通信やりとりを(自動で)行いたい。 ここで問題なのが、クライアントAの要求ポートが15000で、 クライアントBの要求ポートも15000なのです。 同じ既に開いているポートでソケット作成しようとしても、socket()関数はエラーを返してくるのですが、 やり方を工夫すれば、同一ポートでの複数クライアント対応は可能なのでしょうか。不可能なのでしょうか。 可能であれば、やり方、ヒント等教えてください。よろしくお願いします。 追記 (1)TCP/IPでは、同一ポートでソケット作成が可能でした。ネットで探したサンプルプログラムが  そのような動きをしていたのですが、UDPに書換えることはできませんでした。  http://eternalwindows.jp/network/winsock/winsock04s.html (2)UNIXの場合fork()処理後に socket()作成 → bind()で同一ポートでの複数クライアント対応が  上手くいくらしいのですが、Windowsではマルチスレッド等をうまく活用すれば、  fork()と同様の処理が可能になり、目的が達成できるでしょうか。

  • WinsockAPIのrecvfromの受信データがおかしい

    環境は WinXPSP2、VB6SP6です WinsockAPIでUDPのマルチキャスト通信で 定期的にrecvfromでデータを受信しています サーバの配信が止まってる時に recvfromをすると、以前に受信したデータが残っており 同じデータを受信し続けます、返り値はゼロではないです Cならばrecvfromの返り値にゼロが入るのですが・・・ どうすれば受信が終わった(正しく受信できない)ことを判ることができるでしょうか?

専門家に質問してみよう