Совместное использование переменной между различными классами в Tornado - PullRequest
0 голосов
/ 27 января 2019

Я пытаюсь написать приложение 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, но данные не отображаются.

Я использую концепцию глобальной переменной, но безуспешно, поскольку не смог передать обновленную переменную "test" на страницу 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>

Привет ксир,

Спасибо за ваш спонтанный ответ. Я просмотрел предоставленную вами ссылку и, пройдя по ней, понял, что 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 голосов
/ 28 января 2019

У вас есть несколько вариантов:

  1. Если вы хотите иметь длительное соединение, например, если клиент отправляет запрос на IndexHandler, и вы хотите, чтобы клиент ждалпока сообщение не находится в очереди, вы можете преобразовать свой обработчик в сопрограмму.
  2. Если вы хотите немедленно вернуть ответ, независимо от наличия данных в очереди, вы можете использовать * 1007 очереди* method.

Пример для дела № 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(...)
...