Ruby的内存流

时间:2014-05-21 13:33:00

标签: ruby stream protocol-buffers in-memory

使用Protocol Buffers时,当整个对象写入IO时,实际的消息大小就会变为已知。所以我使用以下方法:将对象写入中间流,获取它的大小,然后将包含size int的头部的整个数据写入TCP套接字。

我在下面的代码中不喜欢的是使用真实磁盘文件而不是内存流的message_size函数。

require 'protocol_buffers'

module MyServer
  class AuthRequest < ProtocolBuffers::Message
    required :int32, :vers, 1
    required :int32, :orgID, 2
    required :string, :password, 3
  end

  class MyServer
    def self.authenticate(socket, params)
      auth = AuthRequest.new(:vers => params[:vers], :orgID => params[:orgID], :password => params[:password])
      size = message_size(auth)
      if size.present?
        socket.write([size, 0].pack 'NN')
        auth.serialize(socket)
        socket.flush
      end
    end

    def self.message_size(obj)
      size = nil
      io = File.new('tempfile', 'w')
      begin
        obj.serialize(io)
        io.flush
        size = io.stat.size + 4
      ensure
        io.close
      end
      size
    end
  end
end

控制器:

require 'my_server'
require 'socket'

class MyServerTestController < ActionController::Base
  def test
    socket = TCPSocket.new('192.168.1.15', '12345')
    begin
      MyServer::MyServer.authenticate(socket, {vers: 1, orgID: 100, password: 'hello'})
    ensure
      socket.close
    end
  end
end

1 个答案:

答案 0 :(得分:1)

您可以轻松使用StringIO作为内存流。请注意,它被称为StringIO,因为它是 on 一个字符串,它绝对绑定它是字符串数据 - 它的工作原理同样容易关于二进制数据:

def self.message_size_mem(obj)
  size = nil
  io = StringIO.new
  begin
    obj.serialize(io)
    io.flush
    size = io.size + 4
  ensure
    io.close
  end
  size
end


auth = AuthRequest.new(:vers => 122324, orgID: 9900235, password: 'this is a test for serialization')
MyServer.message_size(auth)
# => 47
MyServer.message_size_mem(auth)
# => 47

io = StringIO.new
auth.serialize(io)
io.flush
io.string
# => "\bԻ\a\u0010ˡ\xDC\u0004\u001A this is a test for serialization"