在Tornado中的不同类之间共享变量

时间:2019-01-27 12:21:18

标签: python http tcp tornado

我正在尝试编写Tornado TCP + HTTP Server应用程序。

我的用例是一个Tornado TCP + HTTP Server应用程序,该应用程序从TCP客户端接受数据并传递数据以将其显示在HTTP服务器托管的网页上。

这是我的龙卷风服务器代码:

#!/usr/bin/env python

import os.path
import tornado.httpserver
import tornado.web
import logging
from tornado.ioloop import IOLoop
from tornado import gen
from tornado.iostream import StreamClosedError
from tornado.tcpserver import TCPServer
from tornado.options import options, define

define("port", default=6642, help="TCP port to listen on")
logger = logging.getLogger(__name__)

test = {}

class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        global test 
        self.render('index.html', test=test)

class EchoServer(TCPServer):
    @gen.coroutine
    def handle_stream(self, stream, address):
        global test 
        while True:
            try:
                test = yield stream.read_until("\n")
                logger.info("Received bytes: %s", test)
            except StreamClosedError:
                logger.warning("Lost client at host %s", address[0])
                break
            except Exception as e:
                print(e)


if __name__ == "__main__":
    options.parse_command_line()
    app = tornado.web.Application( handlers=[
        (r'/', IndexHandler)], 
        static_path=os.path.join(os.path.dirname(__file__), "static"),
        template_path=os.path.join(os.path.dirname(__file__), "templates"))
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    server = EchoServer()
    server.listen(6641)
    logger.info("Listening on TCP port %d",6641)
    IOLoop.current().start()

这是python客户端代码:

# echo_client.py
import socket
import time
counter = 0

host = '192.168.43.59'    
port = 6641              # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
while True:
    s.sendall("s\n")
    counter = counter + 1
    time.sleep(5)

我想将从TCP客户端应用程序接收的数据传递到变量“ test”到呈现模板中,以显示在index.html网页中,但是我没有显示任何数据。

我使用的是全局变量概念,但由于无法将更新的“测试”变量传递给index.html页面而没有成功。

如果有人可以在不同的类或处理程序上使用常见的物品会有所帮助。

我正在使用的Javascript文件是这样:

/* test.js */
var test = ""

function set_test(val)
{
    test=val
}

function show_test()
{
    alert(test);
}

使用的HTML模板是这样的:

<!DOCTYPE html>
<html>
<meta http-equiv="refresh" content="30" />
<head>
    <title>Test</title>
    <script src="{{ static_url('scripts/test.js') }}" 
type="application/javascript"></script>
</head>
<body>
    <input type="button" onclick="show_test()" value="alert" />
    <script type="application/javascript">
        set_test("{{test}}");
    </script>
</body>
</html>

嗨,xyres,

谢谢您的自发答复。我浏览了您提供的链接,经过它之后,我了解到q.get()和q.put()可用于存储和检索您所说的数据。但是我无法以以下方式修改龙卷风服务器代码后,我无法从TCP客户端接收数据,在此之前我至少可以从TCP客户端获取数据。您能告诉我我在做错什么吗?队列实施

这是我的龙卷风服务器代码:

#!/usr/bin/env python

import os.path
import tornado.httpserver
import tornado.web
import logging
from tornado.ioloop import IOLoop
from tornado import gen
from tornado.iostream import StreamClosedError
from tornado.tcpserver import TCPServer
from tornado.options import options, define

define("port", default=6642, help="TCP port to listen on")
logger = logging.getLogger(__name__)

#test = {}
q = Queue(maxsize=2)

class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        #global test
        test = yield q.get 
        self.render('index.html', test=test)

class EchoServer(TCPServer):
    @gen.coroutine
    def handle_stream(self, stream, address):
        #global test
        yield q.put(test)
        yield q.join() 
        while True:
            try:
                test = yield stream.read_until("\n")
                logger.info("Received bytes: %s", test)
            except StreamClosedError:
                logger.warning("Lost client at host %s", address[0])
                break
            except Exception as e:
                print(e)


if __name__ == "__main__":
    options.parse_command_line()
    app = tornado.web.Application( handlers=[
        (r'/', IndexHandler)], 
        static_path=os.path.join(os.path.dirname(__file__), "static"),
        template_path=os.path.join(os.path.dirname(__file__), "templates"))
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    server = EchoServer()
    server.listen(6641)
    logger.info("Listening on TCP port %d",6641)
    IOLoop.current().start()

根据龙卷风文档,似乎可以将队列应用于协程,并且在这里我试图将其复制到两个不同的类中。是一个错误..我是龙卷风的新手,所以请忍受我愚蠢的问题..

1 个答案:

答案 0 :(得分:0)

您有多种选择:

  1. 例如,如果要建立长期运行的连接,如果客户端向IndexHandler发送请求,并且希望客户端等待直到消息在队列中,则可以将处理程序转换为协程。
  2. 如果要立即返回响应,无论队列中数据的可用性如何,都可以使用队列的get_nowait()方法。

案例1的示例:

from tornado.queues import Queue

q = Queue()


class IndexHandler(tornado.web.RequestHandler):
    @gen.coroutine
    def get(self):
        self.data_future = q.get()

        data = yield self.data_future

        self.render('index.html', data=data)

    def on_connection_close(self):
        # set an empty result on the future
        # if connection is closed so that 
        # the messages don't get removed from
        # the queue unnecessariliy for 
        # closed connections
        self.msg_future.set_result(None)

案例2的示例:

from tornado.queues import Queue, QueueEmpty

q = Queue()

def get(self):
    try:
        data = q.get_nowait()
    except QueueEmpty:
        data = None
    self.render(...)