扭曲时线程中的transport.write()出错

时间:2015-06-27 13:29:49

标签: python twisted

我试图制作这个简单的服务器脚本,其中多个客户端连接到它并存储在factory.connected_clients字典中。然后我想显示一个菜单,以便执行服务器的用户可以选择他想要使用的客户端以及他想要发送什么命令(比如在反向shell中)。这是代码:

class RshServer(protocol.Protocol):

    def __init__(self, factory, addr):
        self.addr = addr
        self.factory = factory

    def connectionMade(self):
        address = self.addr.host + ':' + str(self.addr.port)
        self.factory.connected_clients[address] = self
        print '[*] Connection made with ' + address

class RshFactory(Factory):

    def __init__(self):
        self.connected_clients = {}

    def buildProtocol(self, addr):
        return RshServer(self, addr)

def show_server_menu():
    print '1. Show connected clients'
    print '2. Open client interface'
    msg = raw_input('Select an option: ')
    return msg

def show_client_menu():
    print '1. Show all processes'
    msg = raw_input('Select an option: ')
    return msg

def server_interface():
    while 1:
        msg = show_server_menu()
        command = server_commands.get(msg, None)
        if command: command()

def client_interface():
    protocol_name = raw_input('Enter client address: ')
    protoc = rsh_factory.connected_clients.get(protocol_name, None)
    if protoc: 
        msg = show_client_menu()
        protoc.transport.write(msg) 


rsh_factory = RshFactory()

server_commands = {
    '1' : lambda: sys.stdout.write(str(rsh_factory.connected_clients)+'\n'),
    '2' : client_interface
}

reactor.listenTCP(8000, rsh_factory)
reactor.callInThread(server_interface)
reactor.run()

但是,当我选择客户端并执行客户端接口函数时,我收到此错误:

Unhandled Error
Traceback (most recent call last):
  File "rsh_twisted_serv.py", line 58, in <module>
    reactor.run()
  File "/usr/lib/python2.7/dist-packages/twisted/internet/base.py", line 1192, in run
    self.mainLoop()
  File "/usr/lib/python2.7/dist-packages/twisted/internet/base.py", line 1204, in mainLoop
    self.doIteration(t)
  File "/usr/lib/python2.7/dist-packages/twisted/internet/epollreactor.py", line 396, in doPoll
    log.callWithLogger(selectable, _drdw, selectable, fd, event)
--- <exception caught here> ---
  File "/usr/lib/python2.7/dist-packages/twisted/python/log.py", line 88, in callWithLogger
    return callWithContext({"system": lp}, func, *args, **kw)
  File "/usr/lib/python2.7/dist-packages/twisted/python/log.py", line 73, in callWithContext
    return context.call({ILogContext: newCtx}, func, *args, **kw)
  File "/usr/lib/python2.7/dist-packages/twisted/python/context.py", line 118, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
  File "/usr/lib/python2.7/dist-packages/twisted/python/context.py", line 81, in callWithContext
    return func(*args,**kw)
  File "/usr/lib/python2.7/dist-packages/twisted/internet/posixbase.py", line 627, in _doReadOrWrite
    self._disconnectSelectable(selectable, why, inRead)
  File "/usr/lib/python2.7/dist-packages/twisted/internet/posixbase.py", line 257, in _disconnectSelectable
    selectable.readConnectionLost(f)
  File "/usr/lib/python2.7/dist-packages/twisted/internet/tcp.py", line 279, in readConnectionLost
    self.connectionLost(reason)
  File "/usr/lib/python2.7/dist-packages/twisted/internet/tcp.py", line 293, in connectionLost
    abstract.FileDescriptor.connectionLost(self, reason)
  File "/usr/lib/python2.7/dist-packages/twisted/internet/abstract.py", line 207, in connectionLost
    self.stopWriting()
  File "/usr/lib/python2.7/dist-packages/twisted/internet/abstract.py", line 429, in stopWriting
    self.reactor.removeWriter(self)
  File "/usr/lib/python2.7/dist-packages/twisted/internet/epollreactor.py", line 344, in removeWriter
    EPOLLOUT, EPOLLIN)
  File "/usr/lib/python2.7/dist-packages/twisted/internet/epollreactor.py", line 321, in _remove
    self._poller.unregister(fd)
exceptions.IOError: [Errno 2] No such file or directory

我认为这是错误是由于从非反应堆线程调用transport.write()。我对吗?我该怎么解决这个问题?

解决方案:正如@Glyph所说,问题确实是我从非反应堆线程调用transport.write()(在他的回答中有更多细节)。我通过将protoc.transport.write()更改为reactor.callFromThread(lambda: protoc.transport.write(msg))

来使用他提出的解决方案

1 个答案:

答案 0 :(得分:1)

我认为你的意思是从 -reactor线程&#34;中调用。除非明确指定,否则Twisted中的代码不是线程安全的。有关详细信息,请参阅threading documentation。使用reactor.callFromThread从stdio读取线程调用Twisted方法,或使用StandardIO告诉Twisted从标准输入读取。