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 "<Client instance at 0x%s: %s / %s / %s / %s>" % (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()
|