使用TCPServer

时间:2017-05-11 08:08:21

标签: ruby multithreading tcp

对于项目,我需要实现TCP服务器。但过了一段时间,我看到有时候我会丢失消息。这对我来说是一个惊喜,因为我总是被告知TCP不会丢失数据包。

所以我编写了两个小脚本来测试消息的接收,我发现即使它是我能做的最简单的代码,我也会失去一些。

为了使示例简单,我为每个连接创建了一个不同的线程,这与我的生产代码不同(它将是一个像NGNIX一样工作的线程池)。

以下是服务器的代码:

require 'socket'
require 'thread'
require 'timeout'

LIMIT = 100

def get_message (client)
  message = 'nothing'
  begin
    Timeout::timeout(1) do
      message = client.gets
    end
  rescue
    message = 'timeout'
  end
  unless message == nil
    message.chomp!
  end
  message
end


server = TCPServer.new(9000)
queue_message, queue_empty, queue_nil, queue_nothing, queue_timeout  = Queue.new, Queue.new, Queue.new, Queue.new, Queue.new
threads = []

(1..LIMIT).each do
  threads << Thread.start(server.accept) do |client|
    counter = 0
    while counter != LIMIT do
      message = get_message(client)
      case message
        when nil
          queue_nil << message
          break
        when ''
          queue_empty << message
        when 'nothing'
          queue_nothing << message
        when 'timeout'
          queue_timeout << message
        else
          queue_message << message
          counter += 1
      end
    end
    client.close
  end
end

threads.each {|t| t.join}
size = queue_message.size
counter = 0
check = Array.new(LIMIT){Array.new(LIMIT)}
until queue_message.empty?
  message = queue_message.pop.split '::'
  check[message[0].to_i][message[1].to_i] = 1
end
(0..LIMIT - 1).each do |i|
  (0..LIMIT - 1).each do |j|
    if check[i][j] == nil
      puts "#{j}::#{i}"
      counter += 1
    end
  end
end
puts '--------------------------------------'
puts 'Threads are finished'
puts "messages: #{size}"
puts "missing: #{counter}"
puts "nil: #{queue_nil.size}"
puts "empty: #{queue_empty.size}"
puts "nothing: #{queue_nothing.size}"
puts "timeout: #{queue_timeout.size}"
puts '--------------------------------------'

这是客户的代码:

require 'socket'

LIMIT = 100

def get_message (client)
  message = ''
  begin
    Timeout::timeout(GETS_TIMEOUT_SPECS) do
      message = client.gets
    end
    unless message == nil
      message.chop!
    end
  end
  message
end

threads = []
client = []
(0..LIMIT - 1).each do |j|
  threads << Thread.new do
    client[j] = TCPSocket.new('localhost', 9000)
    (0..LIMIT - 1).each do |i|
      message = "#{j}::#{i}"
      client[j].puts message
      puts message
      sleep 1
    end
    client[j].close
  end
end

threads.each {|t| t.join}

最后这是我得到的输出示例:

--------------------------------------
Threads are finished
messages: 8230
missing: 1770
nil: 100
empty: 557
nothing: 0
timeout: 2258
--------------------------------------

有时根本没有损失。 那么我的消息在哪里丢失了?

1 个答案:

答案 0 :(得分:0)

在测试了大多数TCPSocket方法之后,我发现我可以使用recv intsead获取并且不会丢失任何消息。 除此之外,我不再需要使用超时。

以下是我从套接字中读取的内容:

def get_message (client)
    message = ''
    while 1 do
        char = client.recv(8)
        message += char
        if char.length < 8
            break
        end
    end
    unless message == nil
        message.chomp!
    end
    message
end