python异步回调转为同步并实现超时

场景:一个服务端A,一个客户端B,存在一个socket连接。
现在写的是客户端B部分,服务端不可控。
原来是 B先发送一个包,等待A返回指定内容,B再发送下一个包


def do():
    s.send(...)
    yield 1
    s.send(...)
    yield 2
    
    
# 接收到数据后的回调
def callback():
    global f
    next(f)
    
f=do()
next(f)

现在想实现一个timeout,并且实现阻塞。B发送数据后阻塞,直到A返回数据(或5秒内未接受到来自A的返回raise一个错误),请教如何实现?

阅读 5.6k
1 个回答

用 Tornado 的话,写不了几行代码吧。

先作个简单的 Server ,以方便演示:

# -*- coding: utf-8 -*-

from tornado.ioloop import IOLoop
from tornado.tcpserver import TCPServer
from tornado import gen

class Server(TCPServer):
    @gen.coroutine
    def handle_stream(self, stream, address):
        while 1:
            data = yield stream.read_until('\n')

            if data.strip() == 'exit':
                stream.close()
                break

            if data.strip() == '5':
                IOLoop.current().call_at(IOLoop.current().time() + 5, lambda: stream.write('ok 5\n'))
            else:
                stream.write('ok\n')


if __name__ == '__main__':
    Server().listen(8000)
    IOLoop.current().start()

然后,来实现 Client ,基本逻辑是,超时就关闭连接,然后再重新建立连接:

# -*- coding: utf-8 -*-

import functools
from tornado.ioloop import IOLoop
from tornado.tcpclient import TCPClient
from tornado import gen


def when_error(stream):
    print 'ERROR'
    stream.close()
    main()

@gen.coroutine
def main():
    client = TCPClient()
    stream = yield client.connect('localhost', 8000)

    count = 0
    IL = IOLoop.current()
    while 1:
        count += 1
        stream.write(str(count) + '\n')
        print count, '...'

        timer = IL.call_at(IL.time() + 4, functools.partial(when_error, stream))

        try:
            data = yield stream.read_until('\n')
        except:
            break

        IL.remove_timeout(timer)

        print data
        yield gen.Task(IL.add_timeout, IOLoop.current().time() + 1)



if __name__ == '__main__':
    main()
    IOLoop.current().start()


撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题