TCP Socketサーバーとクライアント

  • 両方EventMachine::Connectionで書く
  • serverとclientどちらが先に起動しても良い
  • clientはserverから切断されたら自動再接続する
    • unbindイベント内でreconnectしたらできた
  • clientは適当な文字列を送信して、1秒sleepする。
  • serverはclientから受信した文字列を、少し加工してechoする
    • 他のclientには送らない
  • serverはEM::Channelを使ってclientたちを管理する
  • serverは、新しいclientが接続してきた事を全clientに通知する
  • serverは5秒毎に全clientに時刻を送信する

server.rb

#!/usr/bin/env ruby
require 'rubygems'
require 'eventmachine'

HOST = '0.0.0.0'
PORT = 5000

@@channel = EM::Channel.new

class EchoServer < EM::Connection
  def post_init
    @sid = @@channel.subscribe{|mes|
      send_data mes
    }
    puts "new client <#{@sid}>"
    @@channel.push "new client <#{@sid}> connected\n"
  end

  def receive_data data
    return if data.strip.size < 1
    puts "<#{@sid}> #{data}"
    send_data "echo to <#{@sid}> : #{data}\n"
  end

  def unbind
    puts "unbind <#{@sid}>"
    @@channel.unsubscribe(@sid)
  end
end

EM::run do
  EM::start_server(HOST, PORT, EchoServer)

  EM::add_periodic_timer(5) do
    puts msg = "this is broadcast message : #{Time.now.to_s}\n"
    @@channel.push msg
  end
end


client.rb

#!/usr/bin/env ruby
require 'rubygems'
require 'eventmachine'

HOST = 'localhost'
PORT = 5000
RECONNECT_INTERVAL = 5

@@arr = ['zanmai', 'kazusuke', 'marutaka', 'homu']

class Client < EM::Connection
  def post_init
    EM::defer do
      loop do
        puts msg = @@arr.choice
        send_data msg
        sleep 1
      end
    end
  end

  def receive_data(data)
    puts data
  end

  def unbind
    puts "connection closed - #{HOST}:#{PORT}"
    EM::add_timer(RECONNECT_INTERVAL) do
      reconnect(HOST,  PORT)
    end
  end
end

EM::run do
  EM::connect(HOST, PORT, Client)
end