2017-05-11 48 views
0

对于需要实施TCP服务器的项目。但过了一段时间,我看到有时候我正在丢失信息。这对我来说是一个惊喜,因为我总是被告知TCP不会丢包。与TCPServer丢失的邮件

所以我写了两个小脚本来测试邮件的接收情况,并且我看到我失去了一些,即使它是我能做的最简单的代码。

为了让示例变得简单,我为每个连接创建了一个不同的线程,但我的生产代码不会这样(它将是一个像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 
-------------------------------------- 

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

回答

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