使用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
答案 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"