我正在ruby中实现一个小型的thrift(0.6.0)服务器,以便为另一个具有多个连接(多个客户端)到单个服务器的协议发挥代理作用。我希望能够在服务器端保留每个客户端数据,并在多个调用处理函数的调用中跟踪“会话”参数。
我目前使用Thrift::NonblockingServer
因为SimpleServer
似乎不允许并发连接。
我知道如何使用TCPSocket::peeraddr
,但Thrift::NonblockingServer::IOManager::Worker::run
创建一个临时的MemoryBufferTransport
,其中包含它所读取的帧并将其作为输入/输出协议传递给处理器,因此它似乎是信息不会从那里传下来。
有干净的方法吗?
我正在考虑重新定义上面提到的Thrift::NonblockingServer::IOManager::Worker::run
以在其他参数中包含fd或其他ID来处理或扩充proto实例,但是我还要担心生成的ruby代码的一层( <{1}}中的process_*
方法似乎有点沉重。
我想知道以前有人做过这样的事。
谢谢!
P.S。这与this C++ thrift question
类似答案 0 :(得分:0)
以下是我如何更改Thrift::NonblockingServer::IOManager::Worker::run
以支持此功能。
几点需要注意:
$connections
@@connections
ConnEntry
或者差异类?)。Thread.current
哈希有a namespace pollution issue 首先,在某个中央模块:
module MyThriftExt
$connections={}
class ConnEntry
attr_reader :addr_info, :attr
def initialize(thrift_fd)
@addr_info=thrift_fd.handle.peeraddr
@attr={}
end
def self.PreHandle(fd)
$connections[fd]=ConnEntry.new(fd) unless $connections[fd].is_a? ConnEntry
# make the connection entry as short-term thread-local variable
# (cleared in postHandle)
Thread.current[:connEntry]=$connections[fd]
end
def self.PostHandle()
Thread.current[:connEntry]=nil
end
def to_s()
"#{addr_info}"
end end end
module Thrift class NonblockingServer
class IOManager
alias :old_remove_connection :remove_connection
def remove_connection(fd)
$connections.delete fd
old_remove_connection(fd)
end
class Worker
# The following is verbatim from thrift 0.6.0 except for the two lines
# marked with "Added"
def run
loop do
cmd, *args = @queue.pop
case cmd
when :shutdown
@logger.debug "#{self} is shutting down, goodbye"
break
when :frame
fd, frame = args
begin
otrans = @transport_factory.get_transport(fd)
oprot = @protocol_factory.get_protocol(otrans)
membuf = MemoryBufferTransport.new(frame)
itrans = @transport_factory.get_transport(membuf)
iprot = @protocol_factory.get_protocol(itrans)
MyThriftExt::ConnEntry.PreHandle(fd) # <<== Added
@processor.process(iprot, oprot)
MyThriftExt::ConnEntry.PostHandle # <<== Added
rescue => e
@logger.error "#{Thread.current.inspect} raised error: #{e.inspect}\n#{e.backtrace.join("\n")}"
end
end
end
end
end
end
end
end
然后,在处理程序中的任何位置,您都可以访问Thread.current[:connEntry].addr_info
以获取特定于连接的数据,或者在Thread.current[:connEntry].attr
哈希中存储有关连接的任何内容。