TCP非同期通信でフリーズ

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
みけCAT
記事: 6311
登録日時: 9年前
住所: 千葉県
連絡を取る:

TCP非同期通信でフリーズ

#1

投稿記事 by みけCAT » 9年前

Windows Vista SP2 32ビット、Dev-Cpp4.9.9.2、gcc3.4.2です。
TCPを使った通信対戦のリバーシを作ろうとしています。
とりあえずサーバーに接続するだけのところまで作ったのですが、
サーバーに接続すると、サーバーがフリーズします。
何か足りないコードなどがあるのでしょうか?
もしわかりましたら教えていただけるとありがたいです。
よろしくお願いします。
添付ファイル
netribaasi_error.zip
プログラムです。
(22.75 KiB) ダウンロード数: 52 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

YuO
記事: 942
登録日時: 9年前
住所: 東京都世田谷区

Re: TCP非同期通信でフリーズ

#2

投稿記事 by YuO » 9年前

みけCAT さんが書きました:サーバーに接続すると、サーバーがフリーズします。
ざっと見ただけですが,sendとrecvの取り扱いが間違っているのではないかと思います。
recvの戻り値がSOCKET_ERRORでWSAGetLastError()がWSAEWOULDBLOCKの場合,一度処理をWindowsに返して次のFD_READで続きを読むようにする必要があります。
そうしないと,SOCKET_ERRORの値は-1なので,recv APIがSOCKET_ERRORを返した場合に,
recvlen関数の処理中にrecvedsizeに-1されて,最初の21オクテットの読み込み終了後もrecvedsizeが20以下なので読み込みが終わらない,ということになります。

あと,send APIもlenだけ送信するという保証はありません。
送信サイズが小さくても,戻り値を確認してWSAEWOULDBLOCKに対しての処理を入れる必要があります。

ソースコードを簡単に見ただけではありますが,気になったのは以上でしょうか。

アバター
みけCAT
記事: 6311
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: TCP非同期通信でフリーズ

#3

投稿記事 by みけCAT » 9年前

ありがとうございます。
実装してみたいと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6311
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: TCP非同期通信でフリーズ

#4

投稿記事 by みけCAT » 9年前

フリーズはしないようになりましたが、クライアントが反応しません。
調べてみると、サーバーからデータが送信されないようです。
受信したあと送信するタイミングでsendなどのコードを入れると、
多量に通信して通信エラーと出ます。
どうすればいいのでしょうか?
教えていただけるとありがたいです。
よろしくお願いします。
添付ファイル
netribaasi_error3.zip
送信時に一回sendをするプログラムです。
(25.5 KiB) ダウンロード数: 21 回
netribaasi_error2.zip
プログラムです。
(25.24 KiB) ダウンロード数: 21 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

YuO
記事: 942
登録日時: 9年前
住所: 東京都世田谷区

Re: TCP非同期通信でフリーズ

#5

投稿記事 by YuO » 9年前

みけCAT さんが書きました:調べてみると、サーバーからデータが送信されないようです。
単純に,FD_READより先にFD_WRITEが来て,FD_READでCMD_SANKAを受け取ってもFD_WRITEが来ないため,sendされないだけでしょう。
FD_WRITEは,
  • connectまたはacceptした直後 (WSA付きバージョン含む,以下同じ)
  • send/sendtoにWSAEWOULDBLOCKを理由に失敗した後に,送信可能になった後
に通知されます。
FD_READはドライバのバッファにデータが残っている状態になって初めて通知されるため,accpet直後にはFD_READより先にFD_WRITEが通知されます。
以降,sendを呼び出す機会がサーバー側に存在しないため,FD_WRITEが通知されることは無く,データが送信されることはありません。
なお,FD_READ通知に対してrecvを一度だけ呼び出すことが推奨されています (WSAAsyncSelectのRemarks)。
# FD_WRITE通知に対してはWSAEWOULDBLOCKするまでsendして問題ないことに注意。
みけCAT さんが書きました:受信したあと送信するタイミングでsendなどのコードを入れると、
多量に通信して通信エラーと出ます。
その時のWSAGetLastErrorの値は何ですか。

References)
MSDN: WSAAsyncSelect Function (Windows)
http://msdn.microsoft.com/en-us/library/ms741540.aspx
MSDN: send Function (Windows)
http://msdn.microsoft.com/en-us/library/ms740149.aspx

アバター
みけCAT
記事: 6311
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: TCP非同期通信でフリーズ

#6

投稿記事 by みけCAT » 9年前

FD_READの後は1回のみrecvを呼び出すようにしてみました。
必要な場合はsendするようにしてあります。
多量に通信し通信エラーになる状況は変わりません。
YuO さんが書きました:その時のWSAGetLastErrorの値は何ですか。
今回のコードでは「通信エラー1」と表示されます。
このエラーはプロトコル的なものなので、WSAGetLastErrorは関係ないと思います。
おそらくCMD_SANKAを複数回送ってしまっています。

助けてください。お願いします。
添付ファイル
netribaasi_error4.zip
プログラムです。
(25.99 KiB) ダウンロード数: 20 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

mila

Re: TCP非同期通信でフリーズ

#7

投稿記事 by mila » 9年前

VCで試しに動かしてみましたがいくつか問題点がありそうです。

・gethostbyname関数でWSANOTINITIALISEDエラーが発生しています。WSAStartup関数の呼び出しが必要です。
・accept関数を呼び出すときに第3引数にlen変数を指定していますがこの変数を初期化していません。
・WSOCK_SELECTでbuf変数のサイズを100で宣言していますがgame変数のサイズが100を超えているためにスタック破壊を起こしています。buf変数は十分大きなサイズにした方がよいでしょう。
・FD_READイベントを検知したときにrecvを2段階に分けて呼び出しており、2回目のrecvによって再度FD_READイベントが発生しています。これにより2回目のFD_READイベントの際にrecvlen関数内のrecv関数呼び出しがWSAEWOULDBLOCKエラーになっています。

アバター
みけCAT
記事: 6311
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: TCP非同期通信でフリーズ

#8

投稿記事 by みけCAT » 9年前

mila さんが書きました:・gethostbyname関数でWSANOTINITIALISEDエラーが発生しています。WSAStartup関数の呼び出しが必要です。
修正したつもりです。
mila さんが書きました:・accept関数を呼び出すときに第3引数にlen変数を指定していますがこの変数を初期化していません。
修正したつもりです。
mila さんが書きました:・WSOCK_SELECTでbuf変数のサイズを100で宣言していますがgame変数のサイズが100を超えているためにスタック破壊を起こしています。buf変数は十分大きなサイズにした方がよいでしょう。
修正したつもりです。
buf[1000]にしてみました。
mila さんが書きました:・FD_READイベントを検知したときにrecvを2段階に分けて呼び出しており、2回目のrecvによって再度FD_READイベントが発生しています。これにより2回目のFD_READイベントの際にrecvlen関数内のrecv関数呼び出しがWSAEWOULDBLOCKエラーになっています。
新しいプログラムではrecvlen関数は使っておらず、1回のFD_READで1回だけrecv関数を呼んでいるつもりです。

まだ症状が改善しません。
また、サーバー側で自分の名前(サーバーの設定ダイアログで入力した名前)が表示されないのも気になります。
どこに問題があり、どうすれば解決しそうかを具体的に教えていただけると助かります。
「修正したつもり」のものでも、まだ直っていなければそう言ってください。
すみません。
よろしくお願いします。
添付ファイル
netribaasi_error5.zip
プログラムです。
(26.01 KiB) ダウンロード数: 21 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

mila

Re: TCP非同期通信でフリーズ

#9

投稿記事 by mila » 9年前

修正前のソースを見ていたようで失礼致しました。
修正後のソースで再度動かしてみました。

・WSAAsyncSelect関数にFD_WRITEの指定はおそらく不要です。case FD_WRITEも同様です。
・クライアントとして動作させたときにinitclients関数を読んでいないためにclients変数が初期化されておらず、recvmodeが0のままで誤動作するように見受けられます。
・if(mode=MODE_SERVER && inited==1) { とありますが「=」は「==」のミスではないでしょうか。

アバター
みけCAT
記事: 6311
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: TCP非同期通信でフリーズ

#10

投稿記事 by みけCAT » 9年前

とりあえずうまく通信できるようになったみたいです。
ありがとうございます。
mila さんが書きました:・クライアントとして動作させたときにinitclients関数を読んでいないためにclients変数が初期化されておらず、recvmodeが0のままで誤動作するように見受けられます。
修正しました。
mila さんが書きました:・if(mode=MODE_SERVER && inited==1) { とありますが「=」は「==」のミスではないでしょうか。
修正しました。
mila さんが書きました:・WSAAsyncSelect関数にFD_WRITEの指定はおそらく不要です。case FD_WRITEも同様です。
今のFD_WRITEがある実装の仕方ではダメなのでしょうか?
FD_WRITEがある場合とない場合、それぞれの長所と短所を教えていただければありがたいです。
よろしくお願いします。
添付ファイル
netribaasi_zantei.zip
プログラムです。
(27.15 KiB) ダウンロード数: 52 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

閉鎖

“C言語何でも質問掲示板” へ戻る