handle AVL messages with iodine

2019-09-18 14:17发布

Right now I'm developing a some sort of parser for the messages of the Skypatrol TT8750+ and my threaded TCP server is working. The problem is that it isn't a good approach if there are to many devices connected at the same time. I'm using iodine but I can't make work some code that was given to me. My goal is to receive first a 33bytes message to identify the device and then start to receive 86bytes messages with information of the vehicle.

require 'iodine'

# define the protocol for our service
class TT8750plus
  @timeout = 10
  def on_open
    puts "New Connection Accepted."
    # this file is just for testing purposes.
    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
      po += @expecting
      @expecting = 86
      @msg.clear
    end
    if(length > 0)
      @msg << (buffer[pos, length])
      @expecting = 86 - length
    end
    puts @msg
  end

  def on_close
    @out_file.close
  end
end
# create the service instance
Iodine.listen 12050, TT8750plus
# start the service
Iodine.start

And this error appears on every message

New Connection Accepted.
Iodine caught an unprotected exception - NoMethodError: undefined method `+' for nil:NilClass
iodineServer.rb:26:in `on_message'
iodineServer.rb:1:in `on_data'Iodine caught an unprotected exception - NoMethodError: undefined method `+' for nil:NilClass

Also this implementation doesn't get the messages I need These are the first two lines that I got from this implementation:

0021000a0800000000000120202020202038363332383630323034333433373020
0021000a08000000000001202020202020383633323836303230343334333730200056000a08100020202020202038363332383630323034333433373020014b0000

And these are the first two lines from the threaded implementation

0021000a0800000000000120202020202038363332383630323034333433373020
0056000a08100020202020202038363332383630323034333433373020000b00000013090044709bfb8109e400000000001100000000000067eb11090c1512012e970020000000000005000000000005000000000007 
0056000a08100020202020202038363332383630323034333433373020010b00000013090044709bfb8109e400000000001200000000000067eb11090c1512042e970020000000000005000000000005000000000008

1条回答
劳资没心,怎么记你
2楼-- · 2019-09-18 15:10

This looks like a variation of the untested code I posted earlier.

It seems the issue is with a spelling mistake in the code (probably mine?).

The po += ... should have been pos += ...

require 'iodine'

# define the protocol for our service
class TT8750plus
  @timeout = 10
  def on_open
    puts "New Connection Accepted."
    # this file is just for testing purposes.
    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 # the spelling mistake was here
      @expecting = 86
      puts "wrote:", @msg
      @msg.clear
    end
    if(length > 0)
      @msg << (buffer[pos, length])
      @expecting = 86 - length
    end
    puts("Waiting for more data:", @msg) unless @msg.empty?
  end

  def on_close
    @out_file.close
  end
end
# create the service instance
Iodine.listen 12050, TT8750plus
# start the service
Iodine.start

Again, lacking an emulation for the Skypatrol TT8750+, I can't test the code. But it should be possible to follow error messages to slowly track down these types of issues.

P.S.

To protect from exceptions, consider using Ruby's:

begin
    # code
rescue => e
    # oops something happened. i.e.
    puts e.message, e.backtrace
end

i.e., the on_message method might look like this:

  def on_message buffer
   begin
    length = buffer.length
    pos = 0
    while length >= @expecting
      @msg << (buffer[pos, @expecting])
      @out_file.puts(@msg.unpack('H*')[0])
      length -= @expecting
      pos += @expecting # the spelling mistake was here
      @expecting = 86
      @msg.clear
    end
    if(length > 0)
      @msg << (buffer[pos, length])
      @expecting = 86 - length
    end
    puts @msg unless @msg.empty? # print leftovers for testing...?
   rescue => e
     # oops something happened. React
     puts e.message, e.backtrace
   end
  end

Also, FYI, iodine allows you to control the number of processes (workers) and threads you'r using. See the documentation for details.

查看更多
登录 后发表回答