【问题标题】:Sharing a variable between different classes in Tornado在 Tornado 的不同类之间共享一个变量
【发布时间】:2019-06-20 15:12:24
【问题描述】:

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

我的用例是 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()

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

【问题讨论】:

  • 使用 Tornado 队列:tornadoweb.org/en/stable/queues.html。将接收到的数据放入队列并在您的请求处理程序中检索它,然后呈现模板。
  • 根据龙卷风文档,队列似乎可以应用于协程,在这里我试图将相同的复制到两个不同的类。这是一个错误..我是龙卷风的新手,所以请忍受我的愚蠢问题..
  • 你可以让你的get处理程序成为协程。您使用的是哪个 Python 版本?
  • 嗨 xyres,我正在使用 python 2.7.13

标签: python http tcp tornado


【解决方案1】:

您有多种选择:

  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(...)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-14
    • 1970-01-01
    • 1970-01-01
    • 2016-06-26
    • 2019-07-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多