繁盛しているのはいいけれど、返事が大変だなぁ。 >>1616 みかん(perlでソケットの質問してた方) >> select に <> や read を使うのは不適切です。 > 「クライアントやサーバーとうまく接続できたかどうかを確認する」、 > というような形が正しいselectの > 使われ方だと考えてもいいですか? いいえ。タイムアウトも select の正しい使い方です。 サンプルプログラムを書いてみました。 http://X68000.startshop.co.jp/~68user/tmp/select-sysread.pl echo サーバと echo クライアントです。2つスクリプトを書くのが 面倒だったので、fork して 片方が echo サーバになり、もう片方は echo クライアントとして動作するようにしました。 echo クライアントは echo サーバに接続し、文字列を送り、 それを受け取るだけです。echo サーバは select でソケットを 監視し、マルチスレッドサーバとして動作します。また、 クライアントが接続してから2秒経過したらタイムアウトとして 切断します。 で、これを動かすと、 親:5000 でクライアント待ち 子:localhost:5000 に接続します。 親:127.0.0.1:1291 からの接続を受け付け 子:送信メッセージ: HELLO (*1) 親:127.0.0.1:1291 に反応あり 親:127.0.0.1:1291 からメッセージ受信:HELLO 親:127.0.0.1:1291 へメッセージ送信:Received HELLO 子:受信メッセージ: Received HELLO (*2) 子:5秒眠ります (*3) 親:タイムアウトにより 127.0.0.1:1291 を切断 (*4) 子:新しい接続 (*5) 親:127.0.0.1:1292 からの接続を受け付け 子:送信メッセージ: HELLO AGAIN (*6) 親:127.0.0.1:1292 に反応あり 子:5秒眠ります (*7) となります。 最初は子が親に HELLO と送り (*1)、Received HELLO を受け 取ります (*2)。次に、子は5秒 sleep するので (*3)、親は タイムアウトとして切断します (*4)。 次に、子は新しいソケットを生成し再度親に接続します (*5)。 子は親に HELLO AGAIN と送ります (*6)。ただし、今度は メッセージの最後に改行コードを付けません。そして子は5秒 sleep します (*7)。するとここで親も子も動作が止まり、 永遠にデッドロックします。 なぜなら、親は子からのメッセージを $recv_message = <$sock>; で読んでいるからです。改行コードが送られてこないと、 ここでブロックしてしまいますので、これでは select を 使う意味がありません。 今回は意図的に改行コードを含まない文字列を送りました。 これと同じことが、改行コード以前のデータが到着している けれど、改行コードはパケットロスにより再送中、という 状況でも起こります。 というわけで、こういうときは sysread($sock, $recv_message, 100); などとします。これなら、既に到着しているデータのみを 読みます。100バイト分のデータを読もうとしますが、もし そのとき10バイト分のデータしか届いていなかったら、 そこで sysread から処理が戻り、select まで処理が 進み、正常にタイムアウト処理が行えます。 |