青山です。

On Fri, 7 Jan 2000 12:22:44 +0900,
dn <daisuke / sanpo.t.u-tokyo.ac.jp> 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 <wakou / fsinet.or.jp>