При работе с протокольными буферами реальный размер сообщения становится известен, когда весь объект записывается в IO
. Поэтому я использую следующий подход: записываю объект в промежуточный поток, получаю его размер, а затем записываю все данные с заголовком, содержащим размер 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