[Stackless] Hello, and socket question

Kuros kurosknight at gmail.com
Wed Nov 15 09:47:39 CET 2006


Hello everyone,

I've recently discovered stackless, and it looks ideal for my project (a
python MUD). Unfortuantly, I'm still having some trouble wrapping my brain
around how, exactly, to use stackless.

I played around with the chat server on the Example page, but I must
confess, I don't quite understand it. When I tried to add a player class to
the MUD, I get a:

Exception exceptions.RuntimeError: 'maximum recursion depth exceeded' in
<bound
method Player.__del__ of <Player object at 0x00A9B7B0>> ignored

error.

Source code:

import stackless
import stacklesssocket as socket
import traceback

import mud

class Entity(object):
    def __init__(self):
        self.name = ''
        self.description = ''


class Player(Entity, socket.stacklesssocket):
    def __init__(self, clientSocket, clientAddress, name='',
description=''):
        Entity.__init__(self)
        socket.stacklesssocket.__init__(self, clientSocket)
        self.address = clientAddress

    def close(self):
        # Notify the server.
        if self.disconnectChannel is not None:
            # This will not block.  The channel is set to schedule
            # receivers and return to the sender immediately.
            self.disconnectChannel.send(self)
            self.disconnectChannel = None
        # Do the standard socket closure handling.  But we can't
        # call the underlying function as it doesn't exist on the
        # superclass, and trying to call it there anyway won't get it
        # routed through getattr.
        self.dispatcher.close()


class World(object):
    def __init__(self):
        self.players = {}
        self.nextConnectionID = 1

    def addPlayer(self, clientSocket, clientAddress):
        clientSocket.connectionID = self.nextConnectionID
        player = Player(clientSocket, clientAddress)
        self.players[clientSocket.connectionID] = player
        self.nextConnectionID += 1
        print "Received connection for player #", clientSocket.connectionID,
"from", clientAddress
        return player

    def monitorIncomingConnection(self, player):
        clientSocket.send("Welcome to a less basic Stackless Python MUD
server.\r\n")
        try:
            while clientSocket.connected:
                clientSocket.send("> ")
                line = clientSocket.readline()[:-2].strip()
                words = [ word.strip() for word in line.split(" ") ]
                verb = words[0]

                if verb == "look":
                    clientSocket.send("There are %d users connected:\r\n" %
len(infoByConnectionID))
                    clientSocket.send("Name\tHost\t\tPort\r\n")
                    clientSocket.send("-" * 40 +"\r\n")
                    for clientAddress2, clientSocket2 in
infoByConnectionID.itervalues():
                        clientSocket.send("Unknown\t"+
str(clientAddress2[0]) +"\t"+ str(clientAddress2[1]) +"\r\n")
                elif verb == "say":
                    line = line[4:]
                    secondPartyPrefix = "Someone says: "
                    for clientAddress2, clientSocket2 in
infoByConnectionID.itervalues():
                        if clientSocket2 is clientSocket:
                            prefix = "You say: "
                        else:
                            prefix = secondPartyPrefix
                        clientSocket2.send(prefix + "\"%s\"\r\n" % line)
                elif verb == "quit":
                    clientSocket.close()
                elif verb == "help":
                    clientSocket.send("Commands:\r\n")
                    for verb in [ "look", "say", "quit", "help" ]:
                        clientSocket.send("  "+ verb +"\r\n")
                else:
                    clientSocket.send("Unknown command.  Type 'help' to see
a list of available commands.\r\n")
                stackless.schedule()
        except socket.error:
            print "MonitorIncomingConnection.socket.error"
            traceback.print_exc()

    def runServer(self, host, port):
        listenSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        listenSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        listenSocket.bind((host, port))
        listenSocket.listen(5)

        self.disconnectChannel = stackless.channel()
        self.disconnectChannel.preference = 1
        stackless.tasklet(self.monitorDisconnections)()

        print "Accepting connections on", host, port
        try:
            while listenSocket.accepting:
                clientSocket, clientAddress = listenSocket.accept()
                clientSocket.disconnectChannel = self.disconnectChannel
                player = self.addPlayer(clientSocket, clientAddress)
                stackless.tasklet(self.monitorIncomingConnection)(player)
                stackless.schedule()
        except socket.error:
            print "RunServer.error"
            traceback.print_exc()

        print "RunServer.exit"

    def monitorDisconnections(self):
        try:
            while True:
                clientSocket = self.disconnectChannel.receive()
                print "Received disconnection of #",
clientSocket.connectionID, "from", self.players[clientSocket.connectionID
].address
                self.removePlayer(clientSocket.connectionID)
        except socket.error:
            print "MonitorDisconnections.error"
            traceback.print_exc()
        print "MonitorDisconnections.exit"

    def removePlayer(self, connectionID):
        del self.players[connectionID]

if __name__ == "__main__":
    host = "127.0.0.1"
    port = 3000

    socket.managerRunning = True

    world = World()

    t = stackless.tasklet(world.runServer)(host, port)
    t.run()

    try:
        socket.ManageSockets()
    except KeyboardInterrupt:
        print "** Detected ctrl-c in the console"
    except:
        print "main error"
        traceback.print_exc()
    print "EXIT"


What I am trying to do is this:

Every character (both player and mob) should be instances of the Player or
Character class, and I want a World object to store them all. I want the MUD
to be as abstracted from the networking part as possible. I.e., once the
character instance is in the list of players in the World class, I can just
call like "character.writeWithPrompt('stuff') or whatnot.

 The instance should have a reference to the network layer so I can send
data back out to the connected player (assuming they are a player and not a
mob). If there is no network layer (as in the case of a mob), it just
catches the exception silently.

World is divided into zones, then rooms, etc. I'm planning on zones to have
collections of tasklets for rooms, each item to have one, each mob/player to
have one.

This is all just to give you some idea of what I would like to accomplish
with the code. Any help would be *greatly* appreciated!

Thanks,
-Kuros
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.stackless.com/pipermail/stackless/attachments/20061115/a9d7a19f/attachment.htm>
-------------- next part --------------
_______________________________________________
Stackless mailing list
Stackless at stackless.com
http://www.stackless.com/mailman/listinfo/stackless


More information about the Stackless mailing list