トップページ > 過去ログ > 記事閲覧
TCP/IP通信のデータの送受信処理について
名前:まるお 日時: 2011/10/24 18:09

一度ほぼ完全なデフォルト状態のプログラムでデータの送受信を行ってみて、受信処理の頻度が高ければ 取りこぼしが無くなるのではないかと思い1ms周期で受信処理を行ってみたのですが、 「GetNetWorkDataLength( NetHandle[0] )」をプログラム上でどれだけの頻度で呼び出しても 180msに1回しかデータが届いていないと判断されて受信処理が行われません。 その際処理されるデータは最初に届かなかったデータではなく、最新のものだと思われます。 送信側でWaitTimerをかけない場合、受信側で処理する際に、変数に確保していた容量をオーバーしてプログラムが強制終了するので、 おそらく処理されなかったデータが一斉に受信処理されているのだと思います。 同一PC上では正常に処理が行われ、別のローカル接続されているPCなどを対象にした場合このような現象が発生します。 TCP/IPの通信ではUDPと違い様々な処理が行われていると思うのですが その処理の関係で、DXライブラリのTCP/IP通信では1回の送受信処理の間隔が100ms以上かかるのはやむをえないのでしょうか? 度々申し訳ありませんが、ご回答頂ければと思っています。 よろしくお願いします。 以下に検証に用いたプログラムのコードを記述します。 ////////////////////////////////////////////データ送信側プログラム//////////////////////////////////////////////////////// #include "DxLib.h" #include <stdio.h> int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { char StrBuf[ 256 ] ; // データバッファ IPDATA Ip ; // 接続用IPアドレスデータ int NetHandle ; // ネットワークハンドル int DataLength ; // 受信データ量保存用変数 int sendnum=0; ChangeWindowMode(1); SetDoubleStartValidFlag( TRUE ); SetAlwaysRunFlag(TRUE); if( DxLib_Init() == -1 ) // DXライブラリ初期化処理 { return -1; // エラーが起きたら直ちに終了 } // IPアドレスを設定( ここにある4つのIP値は仮です ) Ip.d1 = 192 ; Ip.d2 = 168 ; Ip.d3 = x ; Ip.d4 = x ; // 通信を確立 NetHandle = ConnectNetWork( Ip, 9850 ) ; // 確立が成功した場合のみ中の処理をする if( NetHandle != -1 ) { // データ送信 NetWorkSend( NetHandle , "繋がったか〜!?" , 17 ) ; // データがくるのを待つ while( !ProcessMessage() ) { // 取得していない受信データ量を得る DataLength = GetNetWorkDataLength( NetHandle ) ; // 取得してない受信データ量が0じゃない場合はループを抜ける if( DataLength != 0 ) break ; } // データ受信 NetWorkRecv( NetHandle , StrBuf , DataLength ) ; // データをバッファに取得 // 受信したデータを描画 DrawString( 0 , 0 , StrBuf , GetColor( 255 , 255 , 255 ) ) ; while(!ProcessMessage()){ sprintf(StrBuf,"%d",sendnum); NetWorkSend( NetHandle,StrBuf, lstrlen(StrBuf)+1 ) ; sendnum++; if(sendnum==10000 || CheckHitKey( KEY_INPUT_ESCAPE )==1) break; WaitTimer(1); } // キー入力待ち //WaitKey() ; // 接続を断つ CloseNetWork( NetHandle ) ; } DxLib_End() ; // DXライブラリ使用の終了処理 return 0 ; // ソフトの終了 } /////////////////////////////////////////////////データ受信側///////////////////////////////////////////////////////////////// #include "DxLib.h" #include <stdio.h> int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { char StrBuf[ 4096 ] ; // データバッファ int NetHandle , LostHandle ; // ネットワークハンドル IPDATA Ip ; // 接続先IPアドレスデータ int recnum=-1; FILE *fp; int DataLength; // 受信データ量保存用変数 ChangeWindowMode(true); SetDoubleStartValidFlag( TRUE ); SetAlwaysRunFlag(TRUE); if( DxLib_Init() == -1 ) // DXライブラリ初期化処理 { return -1; // エラーが起きたら直ちに終了 } fp=fopen("recdata.txt","w"); // 接続してくるのを待つ状態にする PreparationListenNetWork( 9850 ) ; // 接続してくるかESCキーが押されるまでループ NetHandle = -1 ; while( !ProcessMessage() && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 ) { // 新しい接続があったらそのネットワークハンドルを得る NetHandle = GetNewAcceptNetWork() ; if( NetHandle != -1 ) break ; } // 接続されていたら次に進む if( NetHandle != -1 ) { // 接続の受付を終了する StopListenNetWork() ; // 接続してきたマシンのIPアドレスを得る GetNetWorkIP( NetHandle , &Ip ) ; // データが送られて来るまで待つ while( !ProcessMessage() ) { // 取得していない受信データ量が0以外のときはループから抜ける if( GetNetWorkDataLength( NetHandle ) != 0 ) break ; } // データ受信 DataLength = GetNetWorkDataLength( NetHandle ) ; // データの量を取得 NetWorkRecv( NetHandle , StrBuf , DataLength ); // データをバッファに取得 // 受信したデータを描画 DrawString( 0 , 0 , StrBuf , GetColor( 255 , 255 , 255 ) ) ; // 受信成功のデータを送信 NetWorkSend( NetHandle , "繋がったぞ〜!!" , 17 ) ; // 相手が通信を切断するまで待つ while( !ProcessMessage() ) { if( GetNetWorkDataLength( NetHandle ) != 0 ){ DataLength = GetNetWorkDataLength( NetHandle ) ; // データの量を取得 NetWorkRecv( NetHandle , StrBuf , DataLength ); // データをバッファに取得 recnum=(int)atof(StrBuf); fprintf(fp,"recnum:%d\n",recnum); } else{ fprintf(fp,"false\n"); } WaitTimer(1); // 新たに切断されたネットワークハンドルを得る LostHandle = GetLostNetWork() ; // 切断された接続が今まで通信してた相手だった場合ループを抜ける if( LostHandle == NetHandle ) break ; } // 切断確認表示 DrawString( 0 , 16 , "切断しました" , GetColor( 255 , 255 , 255 ) ) ; // キー入力待ち //WaitKey() ; } DxLib_End() ; // DXライブラリ使用の終了処理 fclose(fp); return 0 ; // ソフトの終了 }

Page: 1 |

Re: TCP/IP通信のデータの送受信処理について ( No.1 )
名前:いっち 日時:2011/10/27 01:50

ご納得いただけるか分かりませんが私が行った検証の内容をご報告いたします。 私がテストで使用したソースをアップロードしました。 > h t t p : / / w w w1.axfc.net/uploader/Sc/so/287168.zip&key=dxlib Sever.cpp ... サーバ用のソース Client.cpp ... クライアント用のソース CommonNet.h ... 共通のヘッダ 使用する場合は CommonNet.h 内の kPortNo と kIp を環境に合わせて修正してください。 動作としては、サーバー側からクライアント側へ1フレームにつき1データの送信を kMaxDataCount 回繰り返すというものです。 結果はプログラムの終了時にまとめて Log.txt に出力されます。(なので同じフォルダに入れて実行しないで下さい) 重要なのはクライアント側の Log.txt で1番右の数字(ログはこんな感じです>12978:10:0:17)が受信処理を行ったフレームを表します。 kSpaceSize を 4 の設定(初期状態)で実行すると、まるおさんが今までなさったテストとほぼ同様の結果が得られると思います。 しかし、この値を 512 や 1024 といった値にして、データ量を増やすと、おそらくLAN越しの通信でも受信頻度が上がると思います。 ここから先はかなりうろ覚えで恐縮なのですが、Winsockでは伝送効率を上げる(TCP/IPはヘッダがちょっと大きい)ために ある程度のデータをまとめて送っていたような記憶があります。 Winsock を直にたたけばこういった処理を回避できたはずですが・・・忘れてしまいました。すみません。 できたとしても、伝送効率が悪くなり、あまりお行儀が良いとは思えないので、できるかぎり UDP 等で対応することをお勧めします。 どなたか詳しい方がいらっしゃいましたら、フォローしてくださると助かります。
Re: TCP/IP通信のデータの送受信処理について ( No.2 )
名前:Will 日時:2011/10/27 10:08

> ここから先はかなりうろ覚えで恐縮なのですが、Winsockでは伝送効率を上げる(TCP/IPはヘッダがちょっと大きい)ために > ある程度のデータをまとめて送っていたような記憶があります。 フォローします。 TCP/IPでは送信データが送信側のバッファサイズ、もしくは受信側バッファのサイズに相当になるまで、もしくは一定時間経過するまで送信を行いません。 なぜかというと、TCP/IPでは送受信するさいに伝送ミスを防ぐため、送信データ以外の制御電文をやりとりするので、 小さな電文の送信要求が発生するたびに送信していると、制御電文のほうが多くなってしまいLAN上に余計な負荷をかける事になり逆に遅くなってしまうためです。 バッファサイズはMTUで定義され通常は1500です。 UDPではこのような制限がなく、送信要求が発生するたびに送信します。 ただし、TCP/IPのように受信側の状態を考慮せず送信しますので、受信側のデータ刈り取りが遅いと 受信バッファに入りきらなかったデータが損失します。 一般環境での使用を前提としたソフトで、TCP/IPで数ミリ単位で通信するようなソフトは他ソフトの迷惑になる 場合もあるため避けるべきかと思います。
Re: TCP/IP通信のデータの送受信処理について ( No.3 )
名前:まるお(解決) 日時:2011/10/27 14:06

いっちさん、Willさん、ご回答ありがとうございます。 TCP/IPは信頼性向上のために制御文などがあり、効率よく送受信を行おうとしたとき 連続してデータを送るのは負担が逆に大きくなる可能性があるので、 あまり高速なデータのやり取りを行わない、出来たとしてもメリットが少ない。 TCP/IPを用いるのであれば、1回1回を確実に送受信するものに用いて、 連続して高速にデータのやりとりを行いたい場合はUDPでプログラムを組み、 データの損失などに対応できるように工夫したほうがいいということですね。 とても勉強になりました。 勉強不足な質問に、非常に丁寧に御対応頂きありがとうございました。

Page: 1 |