[英]Message size varies TCPServer Ruby
我正在使用AVL(Skypatrol TT8750 +),它發送的消息(使用TCP)應該是59字節長,但始終會發送第一條消息(該消息包含有關AVL的某些信息,因此用戶可以識別它)的33bytes。
所以問題是,如何處理紅寶石上尺寸不同的消息?
require 'socket'
portnumber = 12050
socketServer = TCPServer.open(portnumber)
while true
Thread.new(socketServer.accept) do |connection|
puts "Accepting connection from: #{connection.peeraddr[2]}"
t = Time.now.strftime("%d-%m-%Y %H%M")
file_name = t + '.txt'
out_file = File.new(file_name, "w+")
begin
while connection
incomingData = connection.gets()
if incomingData != nil
incomingData = incomingData
end
hex_line = incomingData.unpack('H*')[0]
out_file.puts(hex_line)
puts "Incoming: #{hex_line}"
end
rescue Exception => e
# Displays Error Message
puts "#{ e } (#{ e.class })"
ensure
connection.close
puts "ensure: Closing"
end
end
end
這是我正在使用的實驗代碼。
解決方案非常簡單
require 'socket'
require 'celluloid/io'
portnumber = 12050
socketServer = TCPServer.open(portnumber)
while true
Thread.new(socketServer.accept) do |connection|
puts "Accepting connection from: #{connection.peeraddr[2]}"
t = Time.now.strftime("%d-%m-%Y %H%M")
file_name = t + '.txt'
out_file = File.new(file_name, "w+")
messagecounter = 1
begin
while connection
if messagecounter == 1
incomingData = conection.recv(33)
messagecounter += 1
else
incomingData = connection.recv(59)
end
if incomingData != nil
incomingData = incomingData.unpack('H*')[0]
end
out_file.puts(incomingData)
puts "Incoming: #{incomingData}"
end
rescue Exception => e
# Displays Error Message
puts "#{ e } (#{ e.class })"
ensure
connection.close
puts "ensure: Closing"
end
end
end
我只需要一個額外的變量和一個if是否可以自動增加變量,僅此而已。
我正在發布此答案,以解釋我對安德森答案的評論。 大多數代碼不是我的。
if
移出循環 如果if
語句在循環內,則每次循環運行時都會對其進行評估,這會增加CPU指令的數量和每個循環的復雜性。
您可以通過將條件語句移出循環來提高性能,如下所示:
require 'socket'
require 'celluloid/io'
portnumber = 12050
socketServer = TCPServer.open(portnumber)
incomingData = nil
while true
Thread.new(socketServer.accept) do |connection|
puts "Accepting connection from: #{connection.peeraddr[2]}"
# this should probably be changed,
# it ignores the possibility of two connections arriving at the same timestamp.
t = Time.now.strftime("%d-%m-%Y %H%M")
file_name = t + '.txt'
out_file = File.new(file_name, "w+")
begin
if connection
incomingData = conection.recv(33)
if incomingData != nil
incomingData = incomingData.unpack('H*')[0]
out_file.puts(incomingData)
puts "Incoming: #{incomingData}"
end
end
while connection
incomingData = connection.recv(59)
if incomingData != nil
incomingData = incomingData.unpack('H*')[0]
out_file.puts(incomingData)
puts "Incoming: #{incomingData}"
end
end
rescue Exception => e
# Displays Error Message
puts "#{ e } (#{ e.class })"
ensure
connection.close
out_file.close
puts "ensure: Closing"
end
end
end
recv
方法 我可能應該提到的另一種優化(但這里不會實現)是recv
方法調用。
這既是優化又是可能要解決的錯誤的來源。
recv
是系統調用,並且由於網絡消息可能會跨TCP / IP數據包合並(或分段),因此調用recv
可能比處理已解決分段和溢出狀態的內部數據緩沖區要昂貴。
我也建議避免使用每線程客戶端設計。
通常,對於少數客戶而言,這可能並不重要。
但是,隨着客戶端數量的增加和線程的繁忙,您可能會發現系統在上下文切換上花費的資源比實際任務更多。
另一個問題可能是每個線程需要分配的堆棧(如果我沒記錯的話,Ruby線程需要1Mb或2Mb)...在最佳情況下,僅為堆棧提供1000個客戶端將需要超過1 GB的內存分配( m忽略內核結構數據表和其他資源)。
我會考慮使用EventMachine或Iodine(我是碘的作者,所以有偏見)。
事件設計可以為您節省許多資源。
例如(未測試):
require 'iodine'
# define the protocol for our service
class ExampleProtocol
@timeout = 10
def on_open
puts "New Connection Accepted."
# this should probably be changed,
# it ignores the possibility of two connections arriving at the same timestamp.
t = Time.now.strftime("%d-%m-%Y %H%M")
file_name = t + '.txt'
@out_file = File.new(file_name, "w+")
# a rolling buffer for fragmented messages
@expecting = 33
@msg = ""
end
def on_message buffer
length = buffer.length
pos = 0
while length >= @expecting
@msg << (buffer[pos, @expecting])
out_file.puts(msg.unpack('H*')[0])
length -= @expecting
pos += @expecting
@expecting = 59
@msg.clear
end
if(length > 0)
@msg << (buffer[pos, length])
@expecting = 59-length
end
end
def on_close
@out_file.close
end
end
# create the service instance
Iodine.listen 12050, ExampleProtocol
# start the service
Iodine.start
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.