need help with simple server

I cant seem to get this code to run:


#--Start Server in console mode
from pandac.PandaModules import loadPrcFileData
loadPrcFileData("", "window-type none")

import direct.directbase.DirectStart
from pandac.PandaModules import *
from direct.distributed.PyDatagram import PyDatagram
from direct.distributed.PyDatagramIterator import PyDatagramIterator
from direct.task import Task
from direct.showbase.DirectObject import DirectObject
#from direct.actor import Actor


#class Server(DirectObject):
    #def __init__(self):
#--Network address

ADDRESS = "127.0.0.1"
#--tcp/ip connection port
PORT = 9099
#--Backlog sets the max connection attempts we ignore
BACKLOG = 1000
#--Instantate connection classes
cManager = QueuedConnectionManager()
cListener = QueuedConnectionListener(cManager, 0) # <--Changed these to cManager from self.cManager
cReader = QueuedConnectionReader(cManager, 0)
cWriter = ConnectionWriter(cManager, 0)

#--keep track of connections in the array by callback later but for now store them in an array
activeConnections = []

tcpSocket = cManager.openTCPServerRendezvous(ADDRESS, PORT, BACKLOG)
cListener.addConnection(tcpSocket)


#--Handle incomming connections and hand them off to QueuedConnectionManager
def tskListenerPolling(taskdata):
    if cListener.newConnectionAvailable():
        print "Connection Request Recieved..."
        rendezvous = PointerToConnection()
        netAddress = NetAddress()
        newConnection = PointerToCOnnection()

        if cListener.getNewConnection(rendezvous, netAddress, newConnection):
            newConnection = newConnection.p()
                #--remember new connection
            activeConnections.append(newConnection)
                #--Start reading the connection
            cReader.addConnection(newConnection)
            print "Connection Accepted"
        return Task.again

def processDatagram(datagram):
    dataSource = datagram.getConnection()
    iterator = PyDatagramIterator(datagram)
    type = iterator.getString()

    if( type == "PlayerNumRequest"):
        print "Player Number Requested"
        print len(activeConnections)
        retDatagram = PyDatagram()
        retDatagram.addString("PlayerNum")
        retDatagram.addInt32(len(activeConnections))
        cWriter.send(retDatagram, activeConnections[len(activeConnections)-1])

    else: player = iterator.getInt32()
        


#--QueuedConnectionManager starts processing incomming packets here
def tskReaderPolling(taskdata):
    if cReader.dataAvailable():
        datagram = NetDatagram()  # <--Catch incomming data here
    if cReader.getData(datagram):
        processDatagram(datagram) # <--changed process name my need replaced with myProcessDataFunction(datagram)
    return Task.cont




#--add some polling tasks to do connection polling
taskMgr.add(tskListenerPolling, "Poll the connection listener", -39)
taskMgr.add(tskReaderPolling, "Poll the connection reader", -40)

run()

Here is the error I get when I try running this:
I am at a loss

C:\Panda3D-1.7.1\DarkRift\src>python darkriftserver.py
DirectStart: Starting the game.
Traceback (most recent call last):
  File "darkriftserver.py", line 76, in tskReaderPolling
    if cReader.getData(datagram):
UnboundLocalError: local variable 'datagram' referenced before assignment
:task(error): Exception occurred in PythonTask Poll the connection reader
Traceback (most recent call last):
  File "darkriftserver.py", line 99, in <module>
    run()
  File "C:\Panda3D-1.7.1\direct\showbase\ShowBase.py", line 2630, in run
    self.taskMgr.run()
  File "C:\Panda3D-1.7.1\direct\task\Task.py", line 502, in run
    self.step()
  File "C:\Panda3D-1.7.1\direct\task\Task.py", line 460, in step
    self.mgr.poll()
  File "darkriftserver.py", line 76, in tskReaderPolling
    if cReader.getData(datagram):
UnboundLocalError: local variable 'datagram' referenced before assignment

anyone have any idea what is going on with this code???

The error message is telling you that you are referencing a variable called ‘datagram’ that hasn’t yet been assigned to anything. That’s not too surprising if you look at the logic flow:

def tskReaderPolling(taskdata):
    if cReader.dataAvailable():
        datagram = NetDatagram()
    if cReader.getData(datagram):
        processDatagram(datagram)

In this case, you only create a new datagram if cReader.dataAvailable() is true. Then, regardless of that, you call cReader.getData(datagram).

There are two possibilities coming into this function: either cReader.dataAvailable() is true, or it is false. If it is true, the function will work perfectly: it will create a variable called datagram, then pass it to cReader.getData(), and then processDatagram().

But if it is false, the function will fail, because you call cReader.getData(datagram) without first calling datagram = NetDatagram(). So in that case datagram hasn’t been assigned yet.

There’s a simple correction to the code that would solve this problem nicely. I leave it to you to find it. :slight_smile:

David

I had a feeling it was along those line. Something like im telling it to do something with nothing so it cant do what Im asking., The fix im thinkin is probably along the lines of:

if this exists do something with it

if this doesnt exist, wait for it, THEN do something with it. Now i just need to figure out how to correct it.

ok here is what I did and the server *Seems to be running as it doesnt crash,

new code

def tskReaderPolling(taskdata):
    while cReader.dataAvailible():
        datagram = NetDatagram()

        processDatagram(datagram)
    return Task.cont

I replaced the first “if” with “while” and took out " if cReader.getData(datagram):"

which i think is telling the function “while you have this data, do this” instead of “make this data even if its not there and do this”

was that the correct way to solve it?

now i just need to add some print statements to tell me when the server is acculy running :smiley:

You’re thinking in the right direction, but you still need the cReader.getData(datagram) call in there. This is the function that actually gets the data. Without this call, you’re only processing an empty datagram.

David

I see what you mean but im smashing my head against the keyboard now, I know this is got to be real simple but every way I try to add cReader.getData(datagram): back into it I get the error again. tried a for loop, a while, an elif, lol sad thing is i KNOW its a deceptivly simple fix and im just missing it entirely.

EDIT::

INDENTATION STRIKES AGAIN!!!

def tskReaderPolling(taskdata):
    if cReader.dataAvailable():
        datagram = NetDatagram()  # <--Catch incomming data here

        if cReader.getData(datagram): processDatagram(datagram) # <--changed process name my need replaced with myProcessDataFunction(datagram)
    return Task.cont

coded like this , the server starts and runs :unamused:

Nicely solved. :slight_smile:

David

YAY! I R learning!

ok so now I have a problem. I have the server running, and have confirmed as best i can for now with a port scan and ping test, tracert, netstat … and so on that it is opening the correct port and sitting there looking spiffy.

I also have added basic networking code to what will become the client as I learn more and add to it. when started it also opens the correct port then sits waiting .

The problem I have is with both server and client running, I cant get them to talk to one another. The server sits unaware that the client is there and vice versa. SO I suspect the problem lies in my datagram processing. anyway heres the code for the server and client:

client:

from direct.task import Task
from direct.showbase.ShowBase import ShowBase
from pandac.PandaModules import *
#from random import random

#--Server Connection imports
from direct.distributed.PyDatagram import PyDatagram
from direct.distributed.PyDatagramIterator import PyDatagramIterator
from direct.showbase.DirectObject import DirectObject
#from direct.actor.Actor import Actor
#class World(DirectObject):
   # def __init__(self):

#--Setup server connection
ADDRESS = "192.168.1.11"
PORT = 9099
TIMEOUT = 3000 # <-- 3 second connection timeout may need to adjust this later
BACKLOG = 10 # <-- Try to connect to the server 10 times before we give up

#--Setup connection managers
cManager = QueuedConnectionManager()
cReader = QueuedConnectionReader(cManager, 0)
cWriter = ConnectionWriter(cManager, 0)
activeConnections = []

#--Connect to the server
print "Attempting to connect to the server, Please wait....."
connection = cManager.openTCPClientConnection(ADDRESS, PORT, TIMEOUT)

playerNum = 0

#--See if we connected to the server and if so start sending data
if connection:
  cReader.addConnection(connection)
  activeConnections.append(connection)
print "Connection Successful"

def sendOutput(taskdata):
        datagram = PyDatagram()
        datagram.addString("PlayerNumRequest")
        #data = data*10
       # datagram.addFloat64(data)
        if activeConnections:
         for connection in activeConnections:
            cWriter.send(datagram, connection)

        return Task.again

def tskReaderPolling(taskdata):
        while cReader.dataAvailable():
            datagram = NetDatagram()
            if cReader.getData(datagram): processDatagram(datagram)

        return Task.cont


def processDatagram(datagram):
        iterator = PyDatagramIterator(datagram)
       







class DarkRift(ShowBase):

    def __init__(self):
      ShowBase.__init__(self)

#------------load models and stuff here------------------
    #--Lighting
      alight = AmbientLight("alight")
      alight.setColor(VBase4(0.2, 0.2, 0.2, 1))
      alnp = render.attachNewNode(alight)
      render.setLight(alnp)

        #--static models (non-animated)
      self.environ = self.loader.loadModel("Models/Antris V")
      self.environ.setScale(1.25, 1.25, 1.25)
      self.environ.setTwoSided(True)
      self.environ.reparentTo(self.render)
    #tex = loader.loadTexture("Textures/space009.jpg")
    #self.setTexture(tex,1)
      self.environ.setPos(-8, -54, 0)


    #--Background Starfeilds
      self.skysphere = loader.loadModel("Models/Antrisystemstars.bam")
      self.skysphere.setBin("background", 1)
      self.skysphere.setDepthWrite(0)
      self.skysphere.reparentTo(render)
      taskMgr.add(self.skysphereTask, "SkySphere Task")

  #task for rendering the skysphere each frame and moving it relitive to the camera
    def skysphereTask(self, task):
      self.skysphere.setPos(base.camera, 0, 0, 0)
      return task.cont

    #--Animated Models
    

# Main Loop


app = DarkRift()

taskMgr.add(sendOutput, "Send the output to the server", -39)
taskMgr.add(tskReaderPolling, "Poll the connection reader", -38)

app.run()

and server:

import direct.directbase.DirectStart
#from ConfigParser import getfloat
from pandac.PandaModules import *
from direct.distributed.PyDatagram import PyDatagram
from direct.distributed.PyDatagramIterator import PyDatagramIterator
from direct.task import Task
from direct.showbase.DirectObject import DirectObject
#from direct.actor import Actor


#class Server(DirectObject):
    #def __init__(self):
#--Network address

ADDRESS = "192.168.1.11"
#--tcp/ip connection port
PORT = 9099
#--Backlog sets the max connection attempts we ignore
BACKLOG = 1000
#--Instantate connection classes
cManager = QueuedConnectionManager()
cListener = QueuedConnectionListener(cManager, 0) # <--Changed these to cManager from self.cManager
cReader = QueuedConnectionReader(cManager, 0)
cWriter = ConnectionWriter(cManager, 0)
#--keep track of connections in the array by callback later but for now store them in an array
activeConnections = []

tcpSocket = cManager.openTCPServerRendezvous(ADDRESS, PORT, BACKLOG)
cListener.addConnection(tcpSocket)
print "Server running...."

#--Handle incomming connections and hand them off to QueuedConnectionManager
def tskListenerPolling(taskdata):
    if cListener.newConnectionAvailable():
        print "Connection Request Recieved..."
        rendezvous = PointerToConnection()
        netAddress = NetAddress()
        newConnection = PointerToConnection()

        if cListener.getNewConnection(rendezvous, netAddress, newConnection):
            newConnection = newConnection.p()
                #--remember new connection
            activeConnections.append(newConnection)
                #--Start reading the connection
            cReader.addConnection(newConnection)
            print "Connection Accepted"
        return Task.again

def processDatagram(datagram):
    type = datagram.getConnection()
    iterator = PyDatagramIterator(datagram)
    type = iterator.getString()

    if( type == "PlayerNumRequest"):
        print "Player Number Requested"
        print len(activeConnections)
        retDatagram = PyDatagram()
        retDatagram.addString("PlayerNum")
        retDatagram.addInt32(len(activeConnections))
        cWriter.send(retDatagram, activeConnections[len(activeConnections)-1])

   # else: player = iterator.getInt32()
        


#--QueuedConnectionManager starts processing incomming packets here
def tskReaderPolling(taskdata):
    if cReader.dataAvailable():
        datagram = NetDatagram()  # <--Catch incomming data here

        if cReader.getData(datagram): processDatagram(datagram) # <--changed process name my need replaced with myProcessDataFunction(datagram)
    return Task.cont





#--add some polling tasks to do connection polling
taskMgr.add(tskListenerPolling, "Poll the connection listener", -39)
taskMgr.add(tskReaderPolling, "Poll the connection reader", -40)
#taskMgr.add(tskReturnData, "Return Data to the Client", -38)

run()

I suspect they are sending jibberish to each other thus they can never make a connection . also for somereason, the (taskdata) variable always shows as unused in netbeans, not sure if its because its empty until runtime or what . so, any help would be apriciated as always

anyone? even a point in the right direction woul help.

Well, in general, when debugging a problem like this I find it useful to insert print statements throughout the code to prove that it is (or is not) reaching certain parts of the code.

For instance, a print statement in processDatagram() would be helpful to prove that the server is receiving datagrams. If it isn’t, try putting a print statement in sendOutput() to prove that the client is sending them. And so on.

David

ok adding print statements has determined the client is sending datagrams with the sendOutput function BUT the server is not recieving them as it stops at “Server running…” so my tskListenerPolling function is not working as intended.

So the next step is to put a print statement in the beginning of your tskListenerPolling function, to prove that it is getting called at all; and to maybe print the value of cReader.dataAvailable(), to prove whether this ever changes to true or not.

David