読者です 読者をやめる 読者になる 読者になる

FLYING

〈全日本・紀文豆乳飲料シリーズ「麦芽コーヒー」の500ミリリットルパックを扱う小売店が少ないことに遺憾の意を表明する会〉活動記録

一対一チャット

某書籍に載っていたコードを簡略化したもの。cygwin版のRubyではちゃんと動くけど、mswin32版だと $stdin.gets でブロックされて思うように動かないみたい。スレッドとソケットを組み合わせれば色々できそうなんだけど、なかなか思うようにいかないのなー。

うさげ

ruby chat.rb 1234

まず、ポート番号を指定してサーバーを起動する。

ruby chat.rb localhost 1234

次に、ホスト名とポート番号を指定してクライアントを起動する。

発言するときはそのまま送りたい文章を入力。終了したいときは「quit」を送信する。ここら辺の動作はサーバー・クライアント共通になっているので、とても簡単。

ソース

#!/usr/bin/ruby
# chat.rb

require 'socket'
require 'thread'
Thread.abort_on_exception = true

host = ARGV.shift
unless port = ARGV.shift
  host, port = nil, host
  post ||= 0
end

class Chat
  def initialize(sock)
    @sock = sock
  end
  
  def start
    thread = Thread.start { local }
    remote
    thread.exit
  end
  
  def local
    while line = gets do
      line.chop!
      @sock.puts(line)
      break if line =~ /^quit/
    end
  end
  
  def remote
    while line = @sock.gets do
      line.chop!
      puts "> #{line}"
      break if line =~ /^quit/
    end
  end
end

if host then
  sock = TCPSocket.open(host, port)
  puts "connect: #{sock.peeraddr[2]}"
  begin
    chat = Chat.new(sock)
    chat.start
  ensure
    sock.close
  end
else
  s = TCPServer.open(port)
  puts "listen: #{s.addr[1]}"
  loop do
    killme = Thread.start {
      loop { exit if gets =~ /^quit/ }
    }
    sock = s.accept
    puts "accept: #{sock.peeraddr[2]}"
    killme.exit
    begin
      chat = Chat.new(sock)
      chat.start
    ensure
      puts "leave: #{sock.peeraddr[2]}"
      sock.close
    end
  end
end