为什么服务器每1秒更新一次客户端而不是100毫秒 - 完整的源代码可用

时间:2017-01-22 11:00:34

标签: javascript python websocket twisted

我的服务器设置为每隔100毫秒勾选并更新所有客户端 - 请参阅self.TICKS_PER_SECOND = 10,1000/10 = 100毫秒。

然而,"时钟"在HTML中只每1秒更新一次。为什么呢?

如果我一直点击提交按钮,时钟会更快地更新。为什么呢?

app.py

import logging
import sys
from datetime import datetime
import time
current_milli_time = lambda: int(round(time.time() * 1000))

import json
import threading

from twisted.web.static import File
from twisted.python import log
from twisted.web.server import Site
from twisted.web.resource import Resource

from twisted.internet import pollreactor
pollreactor.install()

from twisted.internet import reactor

from autobahn.twisted.websocket import WebSocketServerFactory, \
    WebSocketServerProtocol

from autobahn.twisted.resource import WebSocketResource


class AppGameServerProtocol(WebSocketServerProtocol):

    def onOpen(self):
        """
        """
        self.factory.register(self)
        self.factory.onConnected(self)

    def onConnect(self, request):
        print("Client connecting: {}".format(request.peer))

    def connectionLost(self, reason):
        self.factory.unregister(self)

    def onMessage(self, payload, isBinary):
        self.factory.communicate(self, payload, isBinary)


class AppGameFactory(WebSocketServerFactory):

    def __init__(self, *args, **kwargs):
        super(AppGameFactory, self).__init__(*args, **kwargs)
        self.clients = {}

    def register(self, client):
        self.clients[client.peer] = {"object": client, "partner": None}

    def unregister(self, client):
        self.clients.pop(client.peer)


    def onConnected(self,client):
        client.sendMessage(json.dumps({"type": "connect"}))

    def communicate(self, client, payload, isBinary):
        print "msg received", payload

    def sendMessageAll(self, message):
        for i in self.clients:
            c = self.clients[i]
            c["object"].sendMessage(message)

class SummingThread(threading.Thread):
    def __init__(self, fac):
        super(SummingThread, self).__init__()
        self.fac = fac

        self.TICKS_PER_SECOND = 10
        self.SKIP_TICKS = 1000 / self.TICKS_PER_SECOND
        self.MAX_FRAMESKIP = 5
        self.loops = 0
        self.next_game_tick = current_milli_time()

    def run(self):
        while True:
            self.loops = 0
            while current_milli_time() > self.next_game_tick and self.loops < self.MAX_FRAMESKIP:

                self.fac.sendMessageAll("clock: " + datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3])
                self.next_game_tick += self.SKIP_TICKS
                self.loops += 1



if __name__ == "__main__":
    log.startLogging(sys.stdout)

    factory = AppGameFactory(u"ws://127.0.0.1:8080")
    factory.protocol = AppGameServerProtocol
    resource = WebSocketResource(factory)

    root = Resource()
    root.putChild('', File('index.html'))

    root.putChild(u"ws", resource)

    thread1 = SummingThread(factory)
    thread1.start()

    try:
        site = Site(root)
        reactor.listenTCP(8080, site)
        reactor.run()
    except Exception as e:
        logging.exception("message")

的index.html

<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript">
        window.addEventListener("load", function() {

            var msgReceived = 0

            // create websocket instance
            var mySocket = new WebSocket("ws://localhost:8080/ws");

            // add event listener reacting when message is received
            mySocket.onmessage = function (event) {
                var output = document.getElementById("output");
                // put text into our output div
                msgReceived++;
                output.textContent = event.data + " msgReceived: " + msgReceived;
                //console.log(event.data);
            };

            var form = document.getElementsByClassName("foo");
            var input = document.getElementById("input");

            form[0].addEventListener("submit", function (e) {
                // on forms submission send input to our server
                input_text = input.value;
                mySocket.send(input_text);
                e.preventDefault()
            })
        });

    </script>
<style>
    /* just some super ugly css to make things bit more readable*/
    div {
        margin: 2em;
    }
    form {
        margin: 2em;
    }
</style>
</head>
<body>
    <form class="foo">
        <input id="input"></input>
        <input type="submit"></input>
    </form>
    <div id="output"></div>
</body>
</html>

1 个答案:

答案 0 :(得分:0)

您正在从多个线程调用Twisted API。这是不允许的。您只能从reactor线程调用Twisted API - 除了一些特定的线程安全API。大多数reactor.callFromThread调度函数以在反应器线程中运行。

考虑将SummingThread替换为基于twisted.internet.task.LoopingCall的构造。

例如:

from twisted.internet.task import LoopingCall

def game_tick(factory, skip_count):
    now = datetime.utcnow()
    factory.sendMessageAll(
        "clock: " + now.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
    )


factory = # ...
task = LoopingCall.withCount(partial(game_tick, factory))
task.start(0.1)
# ...
reactor.run()

game_tick每秒会被调用十次(或者,如果因为负载过高或其他一些问题而频率较低,skip_count将被设置为大于一,以表示错过了多少个刻度线)