Package: podsixnet2
PodSixNet - lightweight multiplayer networking library for Python gamesPodSixNet (now calledpodsixnet2) is a lightweight network layer
designed to make it easy to write multiplayer games in Python. It uses
Python’s built in asyncore library and rencode.py (included) to
asynchronously serialise network events and arbitrary data structures,
and deliver them to your high level classes through simple callback
methods.Each class within your game client which wants to receive network
events, subclasses the ConnectionListener class and then implementsNetwork_*methods to catch specific user-defined events from the
server. You don’t have to wait for buffers to fill, or check sockets for
waiting data or anything like that, just doconnection.Pump()once
per game loop and the library will handle everything else for you,
passing off events to all classes that are listening. Sending data back
to the server is just as easy, usingconnection.Send(mydata).
Likewise on the server side, events are propagated toNetwork_*method callbacks and data is sent back to clients with theclient.Send(mydata)method.Thepodsixnet2 mailing
listis good for getting
help from other users.For users of the Construct game making environment for Windows, there is
a tutorial on doing multiplayer networking with podsixnet2,here. Thanks
to Dave Chabo for contributing this tutorial.Here isanother tutorial by Julian
Meyer.Installpip install podsixnet2oreasy_install podsixnet2From sourceFirst make sure you havePython2.4 or greater
installed (python 3 also works).Next you’ll want to get the podsixnet2 source.The module is found inside a subdirectory called podsixnet2 within the
top level folder. There’s an__init__.pyinside there, so you can
just copy or symlink the podsixnet2 sub-directory into your own project
and then doimport podsixnet2, or else you can runsudo python setup.py installto install podsixnet2 into your Python
path. Usesudo python setup.py developif you want to stay up to
date with the cutting edge and still be able to svn/bzr up every now and
then.By default podsixnet2 uses a binary encoder to transfer data over the
network, but it can optionally use theJSONformat or other formats supported by a serialiser which has ‘dumps’ and
‘loads’ methods. If you want to serialise your data using JSON you can
change the first line of Channel.py to ‘from simplejson import dumps,
loads’ or use the built-in json library in Python 2.6 or higher. This
will allow you to write game clients in languages that can’t read the
‘rencode’ binary format, such as Javascript.ExamplesChat example:python examples/ChatServer.pyand a couple of instances ofpython examples/ChatClient.pyWhiteboard example:python examples/WhiteboardServer.pyand a couple of instances ofpython examples/WhiteboardClient.pyLagTime example (measures round-trip time from the server to the
client):python examples/LagTimeServer.pyand a couple of instances ofpython examples/LagTimeClient.pyQuick start - ServerYou will need to subclass two classes in order to make your own server.
Each time a client connects, a new Channel based class will be created,
so you should subclass Channel to make your own
server-representation-of-a-client class like this:frompodsixnet2.ChannelimportChannelclassClientChannel(Channel):defNetwork(self,data):printdatadefNetwork_myaction(self,data):print"myaction:",dataWhenever the client doesconnection.Send(mydata), theNetwork()method will be called. The methodNetwork_myaction()will only be
called if your data has a key called ‘action’ with a value of
“myaction”. In other words if it looks something like this:data={"action":"myaction","blah":123,...}Next you need to subclass the Server class like this:frompodsixnet2.ServerimportServerclassMyServer(Server):channelClass=ClientChanneldefConnected(self,channel,addr):print'new connection:',channelSetchannelClassto the channel class that you created above. The
methodConnected()will be called whenever a new client connects to
your server. See the example servers for an idea of what you might do
each time a client connects. You need to callServer.Pump()every
now and then, probably once per game loop. For example:myserver=MyServer()whileTrue:myserver.Pump()sleep(0.0001)When you want to send data to a specific client/channel, use the Send
method of the Channel class:channel.Send({"action":"hello","message":"hello client!"})Quick start - ClientTo have a client connect to your new server, you should use the
Connection module. Seepydoc Connectionfor more details, but here’s
a summary:Connection.connectionis a singleton Channel which connects to the
server. You’ll only have one of these in your game code, and you’ll use
it to connect to the server and send messages to the server.frompodsixnet2.Connectionimportconnection# connect to the server - optionally pass hostname and port like: ("mccormick.cx", 31425)connection.Connect()connection.Send({"action":"myaction","blah":123,"things":[3,4,3,4,7]})You’ll also need to put the following code once somewhere in your game
loop:connection.Pump()Any time you have an object in your game which you want to receive
messages from the server, subclassConnectionListener. For example:frompodsixnet2.ConnectionimportConnectionListenerclassMyNetworkListener(ConnectionListener):defNetwork(self,data):print'network data:',datadefNetwork_connected(self,data):print"connected to the server"defNetwork_error(self,data):print"error:",data['error'][1]defNetwork_disconnected(self,data):print"disconnected from the server"defNetwork_myaction(data):print"myaction:",dataJust like in the server case, the network events are received byNetwork_*callback methods, where you should replace ‘*’ with the
value in the ‘action’ key you want to catch. You can implement as many
or as few of the above as you like. For example, NetworkGUI would
probably only want to listen for the_connected,_disconnected,
and_errornetwork events. The data for_erroralways comes in
the form of network exceptions, like (111, ‘Connection refused’) - these
are passed straight from the socket layer and are standard socket
errors.Another class might implement custom methods likeNetwork_myaction(), which will receive any data that gets sent from
the server with an ‘action’ key that has the name ‘myaction’. For
example, the server might send a message with the number of players
currently connected like so:channel.Send({"action":"numplayers","players":10})And the listener would look like this:frompodsixnet2.ConnectionimportConnectionListenerclassMyPlayerListener(ConnectionListener):defNetwork_numplayers(data):# update gui element displaying the number of currently connected playersprintdata['players']You can subclassConnectionListeneras many times as you like in
your application, and every class you make which subclasses it will
receive the network events via named Network callbacks. You should call
thePump()method on each object you instantiate once per game loop:gui=MyPlayerListener()while1:connection.Pump()gui.Pump()LicenseCopyrightChris McCormick, 2009-2015.podsixnet2 is licensed under the terms of the LGPL v3.0 or higher. See
the file calledCOPYINGfor details.This basically means that you can use it in most types of projects
(commercial or otherwise), but if you make changes to the podsixnet2
code you must make the modified code available with the distribution of
your software. Hopefully you’ll tell us about it so we can incorporate
your changes. I am not a lawyer, so please read the license carefully to
understand your rights with respect to this code.Why not use Twisted instead?Twisted is a fantastic library for writing robust network code. I have
used it in several projects in the past, and it was quite nice to work
with. That said, Twisted:wants to steal the mainloopis bloated not KISS (it implements many many different protocols)has a weird template launching language when Python should do just
fineis not written 100% for the specfic use-case of multiplayer gamesThese are some of the reasons why I decided to write a library that is
lightweight, has no dependencies except Python, and is dedicated 100% to
the task of multiplayer game networking.