简体   繁体   English

邮件大小因TCPServer Ruby而异

[英]Message size varies TCPServer Ruby

I'm working with an AVL (Skypatrol TT8750+) and the messages that it sends (using TCP) are supposed to be 59bytes long but it always sends a first message (the message has some information about the AVL, so the user can identify it) of 33bytes. 我正在使用AVL(Skypatrol TT8750 +),它发送的消息(使用TCP)应该是59字节长,但始终会发送第一条消息(该消息包含有关AVL的某些信息,因此用户可以识别它)的33bytes。

So the question is, How can I handle those different size messages on ruby? 所以问题是,如何处理红宝石上尺寸不同的消息?

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

This is the experimental code that I'm using. 这是我正在使用的实验代码。

The solution was quite simple 解决方案非常简单

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

I just needed an extra variable and an if to auto increment the variable, and that's it. 我只需要一个额外的变量和一个if是否可以自动增加变量,仅此而已。

I'm posting this answer to explain a comment I made to Anderson's answer. 我正在发布此答案,以解释我对安德森答案的评论。 Most of the code isn't mine. 大多数代码不是我的。


moving the if out of the loop if移出循环

When the if statement is within a loop, it will be evaluated each and every time the loop runs, increasing the number of CPU instructions and the complexity of each loop. 如果if语句在循环内,则每次循环运行时都会对其进行评估,这会增加CPU指令的数量和每个循环的复杂性。

You could improve performance by moving the conditional statement out of the loop like so: 您可以通过将条件语句移出循环来提高性能,如下所示:

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

Optimizing the recv method 优化recv方法

Another optimization I should probably mention (but won't implement here) would be the recv method call. 我可能应该提到的另一种优化(但这里不会实现)是recv方法调用。

This is both an optimization and a possible source for errors that should be addressed. 这既是优化又是可能要解决的错误的来源。

recv is a system call and as network messages might be combined (or fragmented) across TCP/IP packets, it might become more expensive to call recv than to handle an internal buffer of data that resolved fragmentation and overflow states. recv是系统调用,并且由于网络消息可能会跨TCP / IP数据包合并(或分段),因此调用recv可能比处理已解决分段和溢出状态的内部数据缓冲区要昂贵。

Reconsidering the thread-per-client design 重新考虑每个客户端线程的设计

I would also recommend avoiding the thread-per client design. 我也建议避免使用每线程客户端设计。

In general, for a small number of clients it probably doesn't matter much. 通常,对于少数客户而言,这可能并不重要。

However, as clients multiply and threads become busier, you might find the system spends more resources on context switches than actual tasks. 但是,随着客户端数量的增加和线程的繁忙,您可能会发现系统在上下文切换上花费的资源比实际任务更多。

Another concern might be the allocated stack each thread requires (1Mb or 2Mb for Ruby threads, if I remember correctly)... In a best case scenario, 1,000 clients will require more than a GigaByte of memory allocation just for the stack (I'm ignoring kernel structure data table and other resources). 另一个问题可能是每个线程需要分配的堆栈(如果我没记错的话,Ruby线程需要1Mb或2Mb)...在最佳情况下,仅为堆栈提供1000个客户端将需要超过1 GB的内存分配( m忽略内核结构数据表和其他资源)。

I would consider using EventMachine or Iodine (I'm iodine's author, so I'm biased). 我会考虑使用EventMachine或Iodine(我是碘的作者,所以有偏见)。

An evented design could save you many resources. 事件设计可以为您节省许多资源。

For example (untested): 例如(未测试):

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