Viewing file: games-server.py (5.19 KB) -rwxr-xr-x Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) | #!/usr/bin/python
import select
import socket
import errno
import traceback
import fcntl
import os
import sys
import threading
from sys import stdin, stdout, stderr
from threading import Thread
class Client:
WAITING = 1
PARTNERED = 2
DEAD = 3
def __repr__(self):
return "" % (hex(id(self)),
self.sock.fileno(), self.state, self.evmask, len(self.outbuf))
def __init__(self, server, sock):
self.outbuf = ""
self.sock = sock
self.server = server
self.partner = None
self.state = self.WAITING
self.evmask = 0
def destroy(self):
self.state = self.DEAD
partner = self.partner
self.partner = None
if partner:
self.server.del_client(partner)
self.sock.close()
def set_partner(self, partner):
self.partner = partner
self.state = self.PARTNERED
self.register()
def register(self):
evmask = select.POLLHUP|select.POLLNVAL|select.POLLERR
if self.state == self.PARTNERED:
evmask = evmask | select.POLLIN
if len(self.outbuf):
evmask = evmask | select.POLLOUT
if self.evmask != evmask:
self.server.poller.register(self.sock.fileno(), evmask)
self.evmask = evmask
def write_val(self, val):
self.outbuf += val
self.register()
def handle_write(self):
try:
n = self.sock.send(self.outbuf)
except (IOError, OSError, socket.error):
return self.server.del_client(self)
if n <= 0:
return self.server.del_client(self)
self.outbuf = self.outbuf[n:]
self.register()
def handle_read(self):
assert self.state == self.PARTNERED
try:
data = self.sock.recv(8192)
except (IOError, OSError, socket.error):
return self.server.del_client(self)
if not len(data):
return self.server.del_client(self)
self.partner.write_val(data)
class Server(Thread):
def __init__(self, game_port):
Thread.__init__(self)
self.poller = select.poll()
self.asock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
self.asock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.asock.bind(('', game_port))
self.asock.listen(10)
print "Game service running on port" , game_port
self.cnxlist = {}
self.waitlist = []
self.ccount = 0
self.poller.register(self.asock.fileno(), select.POLLIN)
def run(self):
while 1:
try:
evs = self.poller.poll()
except select.error, e:
if e[0] == errno.EINTR:
continue
for I in evs:
if I[0] == self.asock.fileno():
csock, addr = self.asock.accept()
fcntl.fcntl(csock.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
print "\nNew connection from %s, waitlist has %d items" % (addr, len(self.waitlist))
cli = Client(self, csock)
self.cnxlist[csock.fileno()] = cli
self.waitlist.append(cli)
self.ccount += 1
cli.register()
else:
if not self.cnxlist.has_key(I[0]):
assert 0, "Maybe something is broken with FD %s" % I[0]
continue
cnx = self.cnxlist[I[0]]
if (I[1] & (select.POLLHUP|select.POLLNVAL|select.POLLERR)):
self.del_client(cnx)
else:
if (I[1] & select.POLLIN):
cnx.handle_read()
if cnx.state != cnx.DEAD and (I[1] & select.POLLOUT):
cnx.handle_write()
while len(self.waitlist) >= 2:
c1 = self.waitlist[0]
c2 = self.waitlist[1]
self.waitlist = self.waitlist[2:]
c1.write_val("set_peer 1\n") # First in line gets to move first :)
c2.write_val("set_peer 31\n")
c1.set_partner(c2)
c2.set_partner(c1)
def del_client(self, cli):
if cli.state == cli.DEAD:
return
del self.cnxlist[cli.sock.fileno()]
self.poller.unregister(cli.sock.fileno())
cli.destroy()
if cli in self.waitlist:
self.waitlist.remove(cli)
self.ccount -= 1
# This is minimal code to make the process a daemon in the Unix
# environment. See W. R. Stevens "Advanced Programming in the Unix
# Environment". See chapter 13, esp. section 13.3
pid = os.fork ()
if (pid != 0):
os._exit (0)
os.setsid ()
os.chdir ("/")
for fd in range (0, os.sysconf ("SC_OPEN_MAX")):
try:
os.close (fd)
except:
pass
open ("/dev/null", "r") # new stdin
open ("/dev/null", "rw") # new stdout
open ("/dev/null", "rw") # new stderr
# Create the servers - one for each game
iagno1 = Server(26478)
gnibbles1 = Server(26479)
# Start the servers
iagno1.start()
gnibbles1.start()
|