require 'rubygems'
require 'thread'
require 'socket'
#require 'json'
# 这是一个独立运行的程序
# 用于游戏的前端(game_server)与测试引擎(coolie)之间交换数据
# game_server和coolie用socket_client方式实现更加便捷,所以需要一个额外的双向代理
class PeerServer
include Socket::Constants
# 缓存收到的数据,转发给peer
attr_reader :recv_buffer
attr_accessor :peer
def initialize
@recv_buffer = []
@peer = nil
@client_socket = nil
#@mutex = Mutex.new
end
def listen(host, port)
@socket = Socket.new(AF_INET, SOCK_STREAM, 0)
sockaddr = Socket.sockaddr_in(port, host)
@socket.bind(sockaddr)
@socket.listen(1)
end
def has_client?
@client_socket != nil
end
def run
while true
begin
@client_socket, client_sockaddr = @socket.accept_nonblock
clear_buffer_when_connected
puts "got a client!"
# p self
process
rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
close_client
sleep 0.01
IO.select([@socket])
retry
rescue Exception => e
trace(e)
end
end
end
private
def clear_buffer_when_connected
@recv_buffer.clear
@peer.recv_buffer.clear
end
def process
while true
begin
process_receive
process_send
rescue EOFError, Errno::EPIPE
raise Errno::ECONNABORTED
end
sleep 0.01
end
end
def process_receive
# puts "process_receive"
begin
pair = @client_socket.recvfrom_nonblock(2048)
rescue Errno::EAGAIN
return
end
raise Errno::ECONNABORTED if pair[0].empty?
results = pair[0].chomp.split("\n")
results.each do |r|
puts "recv < #{r}"
@recv_buffer << r
end
# r = pair[0].chomp
# return if r.empty?
# #r = @client_socket.readline.chomp
# puts "recv < #{r}"
# @recv_buffer << r unless r.empty?
end
def process_send
# puts "process_send"
return unless @peer.has_client?
s = @peer.recv_buffer.shift
return unless s
puts "send ---> #{s}"
begin
@client_socket.puts s if s
rescue Exception => e
raise Errno::ECONNABORTED
end
end
def close_client
@client_socket.close if @client_socket
puts "client bye"
@client_socket = nil
end
def trace(e)
STDERR.puts e.message
STDERR.puts e.backtrace.map { |line| " #{line}" }
end
end
game_server = PeerServer.new
#game_server.listen('localhost', 20001)
game_server.listen('192.168.254.50', 20001)
coolie = PeerServer.new
coolie.listen('localhost', 20002)
game_server.peer = coolie
coolie.peer = game_server
threads = []
threads << Thread.new { game_server.run }
threads << Thread.new { coolie.run }
threads.each {|thr| thr.join }