I have a problem which I can't understand.
To understand it I wrote a socket client on AS3 and a server on python/twisted, you can see the code of both applications below.
Let's launch two clients at the same time, arrange them so that you can see both windows and press connection button in both windows. Then press and hold any button.
What I'm expecting:
Client with pressed button sends a message "some data" to the server, then the server sends this message to all the clients(including the original sender) .
Then each client moves right the button 'connectButton' and prints a message to the log with time in the following format: "min:secs:milliseconds".
What is going wrong:
The motion is smooth in the client that sends the message, but in all other clients the motion is jerky.
This happens because messages to those clients arrive later than to the original sending client. And if we have three clients (let's name them A,B,C) and we send a message from A, the sending time log of B and C will be the same.
Why other clients recieve this messages later than the original sender?
By the way, on ubuntu 10.04/chrome all the motion is smooth. Two clients are launched in separated chromes.
windows screenshot
Can't post linux screenshot, need more than 10 reputation to post more hyperlinks.
Listing of log, four clients simultaneously:
[16:29:33.280858] 62.140.224.1 >> some data
[16:29:33.280912] 87.249.9.98 << some data
[16:29:33.280970] 87.249.9.98 << some data
[16:29:33.281025] 87.249.9.98 << some data
[16:29:33.281079] 62.140.224.1 << some data
[16:29:33.323267] 62.140.224.1 >> some data
[16:29:33.323326] 87.249.9.98 << some data
[16:29:33.323386] 87.249.9.98 << some data
[16:29:33.323440] 87.249.9.98 << some data
[16:29:33.323493] 62.140.224.1 << some data
[16:29:34.123435] 62.140.224.1 >> some data
[16:29:34.123525] 87.249.9.98 << some data
[16:29:34.123593] 87.249.9.98 << some data
[16:29:34.123648] 87.249.9.98 << some data
[16:29:34.123702] 62.140.224.1 << some data
AS3 client code
package
{
import adobe.utils.CustomActions;
import flash.display.Sprite;
import flash.events.DataEvent;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.events.SecurityErrorEvent;
import flash.net.XMLSocket;
import flash.system.Security;
import flash.text.TextField;
public class Main extends Sprite
{
private var socket :XMLSocket;
private var textField :TextField = new TextField;
private var connectButton :TextField = new TextField;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(event:Event = null):void
{
socket = new XMLSocket();
socket.addEventListener(Event.CONNECT, connectHandler);
socket.addEventListener(DataEvent.DATA, dataHandler);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
addChild(textField);
textField.y = 50;
textField.width = 780;
textField.height = 500;
textField.border = true;
connectButton.selectable = false;
connectButton.border = true;
connectButton.addEventListener(MouseEvent.MOUSE_DOWN, connectMouseDownHandler);
connectButton.width = 105;
connectButton.height = 20;
connectButton.text = "click here to connect";
addChild(connectButton);
}
private function connectHandler(event:Event):void
{
textField.appendText("Connect\n");
textField.appendText("Press and hold any key\n");
}
private function dataHandler(event:DataEvent):void
{
var now:Date = new Date();
textField.appendText(event.data + " time = " + now.getMinutes() + ":" + now.getSeconds() + ":" + now.getMilliseconds() + "\n");
connectButton.x += 2;
}
private function keyDownHandler(event:KeyboardEvent):void
{
socket.send("some data");
}
private function connectMouseDownHandler(event:MouseEvent):void
{
var connectAddress:String = "ep1c.org";
var connectPort:Number = 13250;
Security.loadPolicyFile("xmlsocket://" + connectAddress + ":" + String(connectPort));
socket.connect(connectAddress, connectPort);
}
}
}
Python server code
from twisted.internet import reactor
from twisted.internet.protocol import ServerFactory
from twisted.protocols.basic import LineOnlyReceiver
import datetime
class EchoProtocol(LineOnlyReceiver):
#####
name = ""
id = 0
delimiter = chr(0)
#####
def getName(self):
return self.transport.getPeer().host
def connectionMade(self):
self.id = self.factory.getNextId()
print "New connection from %s - id:%s" % (self.getName(), self.id)
self.factory.clientProtocols[self.id] = self
def connectionLost(self, reason):
print "Lost connection from "+ self.getName()
del self.factory.clientProtocols[self.id]
self.factory.sendMessageToAllClients(self.getName() + " has disconnected.")
def lineReceived(self, line):
print "[%s] %s >> %s" % (datetime.datetime.now().time(), self, line)
if line=="<policy-file-request/>":
data = """<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<!-- Policy file for xmlsocket://ep1c.org -->
<cross-domain-policy>
<allow-access-from domain="*" to-ports="%s" />
</cross-domain-policy>""" % PORT
self.send(data)
else:
self.factory.sendMessageToAllClients( line )
def send(self, line):
print "[%s] %s << %s" % (datetime.datetime.now().time(), self, line)
if line:
self.transport.write( str(line) + chr(0))
else:
print "Nothing to send"
def __str__(self):
return self.getName()
class ChatProtocolFactory(ServerFactory):
protocol = EchoProtocol
def __init__(self):
self.clientProtocols = {}
self.nextId = 0
def getNextId(self):
id = self.nextId
self.nextId += 1
return id
def sendMessageToAllClients(self, msg):
for client in self.clientProtocols:
self.clientProtocols[client].send(msg)
def sendMessageToClient(self, id, msg):
self.clientProtocols[id].send(msg)
PORT = 13250
print "Starting Server"
factory = ChatProtocolFactory()
reactor.listenTCP(PORT, factory)
reactor.run()