为什么服务器每 1 秒而不是 100 毫秒更新一次客户端 - 提供完整的源代码
Why server is updating clients every 1 second instead of 100ms - full sourcecode available
我的服务器设置为每 100 毫秒更新一次所有客户端 - 请参阅 self.TICKS_PER_SECOND = 10
,1000/10 = 100 毫秒。
然而,html 中的 "clock" 每 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>
您正在从多个线程调用 Twisted API。这是不允许的。您只能从反应器线程调用 Twisted API——除了几个特定的 thread-safe 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
将设置为大于 1 以指示有多少滴答错过了)。
我的服务器设置为每 100 毫秒更新一次所有客户端 - 请参阅 self.TICKS_PER_SECOND = 10
,1000/10 = 100 毫秒。
然而,html 中的 "clock" 每 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>
您正在从多个线程调用 Twisted API。这是不允许的。您只能从反应器线程调用 Twisted API——除了几个特定的 thread-safe 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
将设置为大于 1 以指示有多少滴答错过了)。