From: Wakou Aoyama Date: 2000-01-19T03:29:20+09:00 Subject: [ruby-list:20267] Re: non-block IO with TCPSocket 青山です。 On Fri, 7 Jan 2000 12:22:44 +0900, dn wrote: > loop do > print "." > > activate = select socks,nil,nil,0 > > next if activate.nil? select() は timeout 時に nil を返しますから、timeout を永遠に待たせれ ば、決して nil を返す事は無く、このループは不要になります。最後の2行 をまとめて、IO::select(socks) で十分でしょう。(そうならなければ、ruby のバグという事ですよね?) > if tcpsock.eof? eof? は、次の1文字が読み込めなかった場合に true になり、それを実際に 読み込んで確認していますが、socket に関しては接続している限りは次の1 文字が読み込める可能性があるので、延々とその時を待ち続ける事になります。 これは max_size または eof まで読み込む read() も同様で、max_size に行 き付けば良いのですが、そうでなければ、延々と待ち続けます。 回避策としては、行指向である場合には、gets() が手軽です。行毎に処理が 帰ってきますし、改行が来ない場合には、延々と待ち続けてくれて良いわけで すから。 sock = TCPSocket.open("localhost", "echo") while line = $stdin.gets sock.write(line) print(sock.gets) end sock.close 一方、行指向で無い場合には、eof を待たない、相手からのデータが途切れれ ば、max_size 以下であろうが、eof でなかろうが、そこまでのデータを返す、 sysread() を使用する事になるでしょう。 sock = TCPSocket.open("0", "echo") Thread.start do loop do IO::select([sock]) begin print sock.sysread(4096) rescue EOFError # End of file reached break end end end while line = $stdin.gets length = line.length while 0 < length IO::select(nil, [sock]) length -= sock.syswrite(line[-length..-1]) end end sock.close unless sock.closed? これは相手が返すデータが不明な場合の例です。何かプロンプトのようなもの がある場合には Thread は不要で、そのプロンプトまで sysread() のループ を繰り返せば良いです。 さらに、プロンプトを待ってから次の処理をするような場合には、別 Thread にしてしまうと同期が必要になるので、むしろ分けない方が簡単です。また、 そのような場合には telnet.rb も便利です。 ----- あ、telnet.rb の write() って、間違っていますね。よく問題が発生しなかっ たものだ... telnet.rb-1.10.gz を in.coming に入れて置きました。1.4 系 でも動くと思いますので、そちらへもお願いします。(cgi.rb の 1.10 も 1.4 系でも大丈夫と思います。) -- 青山 和光 Wakou Aoyama