簡體   English   中英

郵件大小因TCPServer Ruby而異

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM