イベントを受信するまで待機する方法について – プログラミング – Home

イベントを受信するまで待機する方法につ...
 
通知
すべてクリア

[解決済] イベントを受信するまで待機する方法について


気合だぁ
 気合だぁ
(@気合だぁ)
ゲスト
結合: 20年前
投稿: 6
Topic starter  

ある関数( 以下、xxxEvent( ) )内で recvfrom( ) を行っているのですが、その
recvform( ) がデータを受信するまで xxxEvent( ) を抜けないようにしたいと思ってい
ます。
以下のような感じでプログラムを組んでいます。

BOOL Cxxxx::xxxEvent( .... )
{
int nSendSz = sendto( ..... ) ;
.
. ( 略 ) -> sendto( ) の実行結果のチェックを行っている
. 失敗したら return( FALSE ) ;
.
// sendto( ) に成功したので recvfrom( ) を行う
int nRecvSz = recvfrom( ..... ) ;
.
. ( 略 ) -> recvfrom( ) の実行結果のチェックを行っている
. 失敗したら return( FALSE ) ;
.

return( FALSE ) ;
}

このままでは、データを受信する前に xxxEvent( ) を抜けてしまうので困っています。
情報を知っている方は教えていただけると助かります。

環境
Windows XP sp1
Visual C++ .NET MFC


引用未解決
トピックタグ
PAI
 PAI
(@PAI)
ゲスト
結合: 23年前
投稿: 359
 

recvfrom() が具体的に何をしているかがわからないので確実なことはいえませんが、
受信が終わっているか否かを何らかの方法で知ることが出来るのであれば、

while( true ){
if( /* recvfrom からの受信が終わった */ ){
break;
}
Sleep( /* 適当な時間 */ );
}

とすればよいかと思いますが・・・


返信引用
気合だぁ
 気合だぁ
(@気合だぁ)
ゲスト
結合: 20年前
投稿: 6
Topic starter  

recvfrom( ) は、ある相手からのデータを受信しているのですが、その recvform( ) が
データを受信するまでは、xxxEvent( ) を抜けたくない・・・ということです。
ちなみに、受信が終わったか終わっていないのを判断するにはどうしたらいいのでしょ
うか?


返信引用
REE
 REE
(@REE)
ゲスト
結合: 23年前
投稿: 240
 

逆に質問ですが、
あなたが提示している「ある相手からのデータを受信している」という情報だけから、
それを回答できる人がいると思われているのでしょうか?


返信引用
気合だぁ
 気合だぁ
(@気合だぁ)
ゲスト
結合: 20年前
投稿: 6
Topic starter  

確かに、この文面じゃ分かりませんね。
大変申し訳ございませんでした。

ある相手とは、シリアル通信している Ether-422 変換器なのですが、こっちから
sendto( ) してすぐに recvfrom( ) してもデータが受信できないということが発覚した
ため今回のような質問をさせていただきました。
いろいろ、自分自身でも調べたのですが WaitForSingleObject( ) という関数を使うと
recvfrom( ) 時のタイムアウトも監視できるようなことを言っていたので早速使ってみ
ましたが、第一引数の HANDLE に何を指定すればいいのか分からなくなってしまいまし
た。
その辺も、すみせんが教えていただけると幸いです。


返信引用
九条
 九条
(@九条)
ゲスト
結合: 20年前
投稿: 4
 

横槍失礼します。
recvfrom のタイムアウトを検出したところで、あなたの要求バイト分のデータが
すべてくるとは限りません。
極論1バイトだけ取得できたのでイベントが発生するということがありえます。
ですので、必要としているバイト数が事前にわかっているのなら、

int getBytes = 0;
while(1) {
int curBytes = recvfrom(...);
if( curBytes != 0 ) {
getBytes += curBytes;
if( getBytes >= 必要なバイト数 ) break;
}
Sleep(1);
}

とかやるのが常套手段ではないかと思います。
# PAIさんの回答とほとんど同じですね(^^;;;


返信引用
アイススケーター
 アイススケーター
(@アイススケーター)
ゲスト
結合: 22年前
投稿: 280
 

sendtoやrecvfromを使っているところをみると、UDP/IPのことではないのですか?

基本的には、この関数を利用する場合は、スレッドで処理し、メインのプログラムでタイマー
監視しています。

  キャンセルの場合は、WSACancelBlockingCall()を利用


返信引用
ぽけらった
 ぽけらった
(@ぽけらった)
ゲスト
結合: 20年前
投稿: 4
 

送受信でスレッド生成するのが普通というか・・・。

CreateEvent
CreateThread
WaitForSingleObject or WaitForMultipleObjects


返信引用
気合だぁ
 気合だぁ
(@気合だぁ)
ゲスト
結合: 20年前
投稿: 6
Topic starter  

現在、こんな感じで処理を行っています。

CxxxxxClass::FuncAxxxx( void )
{
// この関数は 30 秒間隔でメインから呼び出される
FuncBxxxx( ) ;
}

CxxxxxClass::FuncBxxxx( void )
{// この関数の前に、UDP Socket はオープンしています
HANDLE hSocketEvent = WSA_INVALID_SOCKET ;
INT nStatus = 0 ;

// 正常に送信できたと仮定して・・・
sendto( .... ) ;

hSocketEvent = WSACreateEvent( ) ;
if( hSocketEvent != WSA_INVALID_SOCKET )
{
nStatus = WSAEventSelect( nSocket , hSocketEvent , FD_READ ) ;
if( nStatus != SOCKET_ERROR )
{
WSANETWORKEVENTS events ;
INT nRtn ;
nRtn = WSAWaitForMultipleEvents( 1 , &hSocketEvent , FALSE ,
5000 , FALSE ) ;
switch( nRtn )
{
case WSA_WAIT_FAILED :
// エラー処理
break ;
case WSA_WAIT_TIMEOUT :
// エラー処理
break ;
default :
if( WSAEnumNetworkEvents( nSocket ,
hSocketEvent , events ) != SOCKET_ERROR )
{
if( events.lNetworkEvents & FD_READ )
{
WSAResetEvent( hSocketEvent ) ;
// ここで、割り込みが発生してしまう
INT nSize = recvfrom( .... ) ;
}
}
break ;
}
}
}
}

という感じで、処理を行っているのですが、自分で採取したログを見ると
sendto( ) の後に FuncAxxxx( ) がメインから呼ばれてしまい(メインからの割り込
み)再度 Sendto( ) してしまいます。しょっちゅうではないですがかなりの回数で発生
しています。
recvfrom( ) の前の処理が悪いのは分かっているのですが・・・・

よろしければ、こんな感じで作って見たら・・・というサンプルがありましたら教えて
いただけますか?
すみませんが、よろしくお願いいたします。


返信引用
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

受信するまでの間、何か別の処理をしたいというのでなければ、
わざわざ非同期モードを使用する必要は無いのではないでしょうか。

sendto( .... ) ;
INT nSize = recvfrom( .... ) ; // 何か受信するまで関数から戻らない

※WSAEventSelectを呼び出すとソケットは非同期モードになり、
処理が完了する前に送受信関数からすぐ戻るようになります。


返信引用
気合だぁ
 気合だぁ
(@気合だぁ)
ゲスト
結合: 20年前
投稿: 6
Topic starter  

そもそも、recvfrom( ) でタイムアウトを検知できるのでしょうか?
もし検知できるのであれば、わざわざWSACreateEvent( ) や WSAEventSelect( ) などを
使う必要はないのですが・・・
ちなみに、select( ) を使ってみましたがやはり割り込みは発生してしまいました。
それと、FuncBxxxx( ) 内の処理を全て #if 0 ~ #endif にしたところ、期待通り 30秒
周期で FuncBxxxx( ) が呼び出されましたのでメインは問題なしでした。


返信引用
Bosscat
 Bosscat
(@Bosscat)
ゲスト
結合: 23年前
投稿: 73
 

はじめましてBosscatと申します。
たまたま立ち寄ったので、ついでに辻レスを・・・

ちょっと意味が取れなかった部分もあるのですが、、、
(タイムアウトうんぬんの個所)
・送信 -> 受信がペアである
で良いのですか?

ソケットプログラムにおいて
コネクション型、コネクションレス共通の話ですが
・送信関数1回に対する受信関数の呼び出し回数は1回とは限らない
というところを見落としているように見受けられます。

17:53:38のソースを見る限りsendto():recvfrom()=1:1 に見えますが、
1:nである必要があるでしょう。

コネクションレス型のソケットは特に
受信終了こ検知する方法はデータをチェックするしかありません。
(バイト数、ターミネータ文字列等)
もし、これらによって検知する手段が無いとしたら
通信プロトコルそのものの問題だと思われます。

以上、長文失礼!


返信引用
Bosscat
 Bosscat
(@Bosscat)
ゲスト
結合: 23年前
投稿: 73
 

追記
・送信関数1回に対する受信関数の呼び出し回数は1回とは限らない
もちろん
送信関数(送信側ノードで呼ばれる)
受信関数(受信側ノードで呼ばれる)
です。

ついでに
・送信バッファ・受信バッファを常に意識してコーディングした方が良いです。
・複数回の送信関数によって送信したデータが(勝手に)1つに纏められて
 受信関数1回で受信できることもあります。
・ほとんどのOSの実装は
  1) 送信時にはなるべく纏めて送る。
  2) 受信時にはなるべく早くバラバラに受信する。
です。
 これは以下の意図があります。
  ・送信時のパケットヘッダ及びパディング分の情報量の節約為。
  ・受信バッファのオーバーフローを抑止する為。
以上


返信引用
気合だぁ
 気合だぁ
(@気合だぁ)
ゲスト
結合: 20年前
投稿: 6
Topic starter  

解決しました。
皆さん、どうもありがとうございました。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました