プロが教える店舗&オフィスのセキュリティ対策術

Cのプログラムでインターバル処理と配信データの受信をselectで制御するとき、配信データの受信後に、インターバルの引数をNULLにするとその後にはインターバルでは跳ねなくなってしまいます。
前回のインターバルの設定を替えずに、selectする方法を
どなたかご存知でしたら教えてください。

A 回答 (4件)

基本的には以下の考え方をとります。


1.selectを行う。
2.timeoutならタイムアウト処理を行い、次のタイムアウト時間は60秒にする。
3.電文受信なら受信処理を行う。但し、次のタイムアウト時間は、前回使ったタイマーの残り時間とする。

問題は、selectが電文受信により終了したとき、タイマーの残り時間をどうやって取得するかです。これに対するシステムコールは提供されていません。従って、以下のようにします。selectの直前で現在の時刻を取得(T1とする)。次にselectの直後で現在の時刻を取得する(T2とする)T2-T1がselectに要した時間となる。従って、前回タイマーの残り時間-(T2-T1)が、次に発行する時のタイマーの時間となります。
前回タイマーの残り時間は、最初又はタイムアウト直後は60秒から開始し、電文受信によるselect終了を継続している間はそれを持ち回ります。
次に、現在時刻の取得ですが、0.001秒のオーダーで必要と言うことですので、gettimeofdayを使用します。これによりマイクロ秒オーダーで現在時刻が取得出来ます。
又、本件とは直接は関係ありませんが、電文受信とタイムアウトの切り分けをFD_ISSETで行っていますが、それは確実に動作していますか。厳密に言えば、以下の手順を踏むべきです。
1.selectの戻り値を取得
2.戻り値=0でタイムアウト
3.戻り値>0電文受信
4.戻り値<0シグナル補足による終了
シグナル補足による終了を考慮する必要がなければ、現行のままでも良いかと思いますが。
コーディングイメージは
FLG=1をタイムアウトとすると
FLG=1
while(1){
ディスクリプタの設定
if (FLG==1){
timeoutへ60秒をセット
}else{
timeout-(T2ーT1)
}
T1を取得(gettimeofday)
select(上記で求めたtimeoutを使用)
T2を取得(gettimeofday)
if (電文受信によるselect完了){
FLG=0
受信処理
}else{
FLG=1
インタバル処理
}
}
時間の引き算は秒とマイクロ秒がありますので、それなりの計算が必要です。たぶんbunarinさんなら判ると思いますのでこれは省略します。
不明点があれば、再度質問して下さい。
    • good
    • 0

#3です。


前回の回答に以下の点を追記します。
1.select(...&timeout.tp )でtimeout.tp の内容が破壊されることがあります。従って
if (FLG==1){
残タイマー=60(残タイマーはtimeoutと同じ型)
}else{
残タイマー=残タイマー-(T2-T1)
}
timeout = 残タイマー
としてtimeout をselectの引数とするようにしてください。

2.残タイマーを計算したとき、残タイマーが負になることがあるかもしれませんので、残タイマーが負の場合は
残タイマーに0をセットする部分を追加しておいてください。
3.受信処理に要する時間は考慮していません。その時間まで考慮する必要があるなら、T2は受信処理完了後の時間としてください。
    • good
    • 0
この回答へのお礼

>問題は、selectが電文受信により終了したとき、
>タイマーの残り時間をどうやって取得するかです。
>これに対するシステムコールは提供されていません。
そうですか、selectを呼んでしまうとやはり、前回の
timeoutの設定がなくなってしまうのは、
自前で対処するしかないんですね。

配慮の行き届いた回答をしていただき
大変参考になりました。
ありがとうございました。

お礼日時:2004/05/19 09:24

行いたいことは、以下の事でよいでしょうか。


1.一定間隔(60秒)でインターバル処理を実行したい。
2.但し、その間にデータを受信した場合は、受信処理を行いたい。
3.受信処理を行った後は、受信処理後、60秒後にインタバル処理が実行されるのではなく、以前に発行したタイマーを含めて、そこから60秒後に、インタバル処理を行いたい。(要は受信処理に関係なくインタバル処理は60秒間隔で行いたい)
4.上記に対して全てyesと言う前提として、タイマーの精度は秒程度のオーダーで良いでしょうか。(つまり59~61秒程度の揺らぎはOKですか。)それとも、更に細かい精度で、60秒に1回起動されることを要求されますか?

この回答への補足

1,2,3 全てYesです。

4は0.001秒まで必要です。

よろしくお願いします。

補足日時:2004/05/18 14:08
    • good
    • 0

インターバル処理とはなんのことでしょうか?


>インターバルでは跳ねなくなってしまいます。
具体的にはどういうことでしょうか?
>インターバルの引数をNULLにする
インターバル処理の引数はどのようになっていますか?
また、どのような機能をもっていますか?

この回答への補足

>インターバル処理とはなんのことでしょうか?
一定間隔で処理をするためのselectの単にタイムアウトの設定のことです。

timeout.tv_sec = 60;
timeout.tv_usec = 0;
ret = select(0,NULL,NULL,NULL,&timeout);

>>インターバルでは跳ねなくなってしまいます。
>具体的にはどういうことでしょうか?

while( 1 ){
FD_ZERO( &readfds );
FD_SET( channel, &readfds );

timeout.tp.tv_sec = 60;
timeout.tp.tv_usec = 0;

/* select によりイベント待ち */
status = select( FD_SETSIZE, &readfds, NULL, NULL, &timeout.tp );

if( FD_ISSET( channel, &readfds ) ){
// 受信処理
} else {
// インターバル処理
}
}
こう書くとインターバル処理のときだけでなく
受信処理の時もタイマーが再設定されてしまいますが、
本来やりたいのはインターバル処理の時だけselectにタイマーを設定したいので
int FLG=1;
while( 1 ){

FD_ZERO( &readfds );
FD_SET( channel, &readfds );

timeout.tp.tv_sec = 60;
timeout.tp.tv_usec = 0;

/* select によりイベント待ち */
if( FLG==1 ){
select( FD_SETSIZE, &readfds, NULL, NULL, &timeout.tp );
} else{
select( FD_SETSIZE, &readfds, NULL, NULL, NULL );
}

if( FD_ISSET( channel, &readfds ) ){
// 受信処理
FLG=0;
} else {
// インターバル処理
FLG=1
}
}
と書くと今度は受信処理を一度行うと
タイムアウトが利かなくなってしまいます。
そこで受信処理後のselectを実行するときに
直前で設定したタイムアウトの設定を消すことなく
実行するにはどうすればよろしいでしょうか?

補足日時:2004/05/16 23:37
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!