对于项目,我需要实现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
--------------------------------------
有时根本没有损失。 那么我的消息在哪里丢失了?
答案 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