Network pyDatagram send error

Hi all,

I was wondering what could be wrong with the following code, that is trying to send a pyDatagram to all connected clients.

If i run this code, i get an error on the cWriter.send part.

AssertionError:!_shutdown at line 167 of c:\buildslave\release_sdk_win32\build\panda3d\panda\src\net\connectionWriter.cxx

    # broadcast a message to all clients
    def myNewPyDatagram(self):
        # Send a test message
        myPyDatagram = PyDatagram()
        myPyDatagram.addUint8(PRINT_MESSAGE)
        myPyDatagram.addString("Hello, world!")
        return myPyDatagram

    def tskBBC(taskdata):
        for aClient in activeConnections:
            TestDatagram = myNewPyDatagram(self)
            cWriter.send(TestDatagram,aClient)
        return Task.cont

Any ideas as to what might be wrong?

thx
Badger

TCP or UDP? I don’t know much about TCP, but here’s how it would work for UDP:

PORT = 4321

cManager = QueuedConnectionManager()
cReader = QueuedConnectionReader(cManager, 0)
cWriter = ConnectionWriter(cManager, 0)
connection = cManager.openUDPConnection(PORT)

def tskBBC(taskdata): 
    for aClient in activeConnections: 
        TestDatagram = myNewPyDatagram(self) 
        cWriter.send(TestDatagram, connection, aClient) 
    return Task.cont

What’s on line 167?

It’s telling you that your ConnectionWriter has already destructed or been otherwise cleaned up. Something is therefore broken in the way you are creating and storing your ConnectionWriter.

This can also happen if you allow your ConnectionManager to destruct, which automatically invalidates any objects it is managing.

David

Thanks for the replies!

import direct.directbase.DirectStart 
from pandac.PandaModules import * 
from direct.distributed.PyDatagram import PyDatagram 
from direct.distributed.PyDatagramIterator import PyDatagramIterator 
from direct.showbase.ShowBase import ShowBase
from direct.task import Task
from direct.showbase.DirectObject import DirectObject
from direct.gui.OnscreenText import OnscreenText

class World(DirectObject):
  #Macro-like function used to reduce the amount to code needed to create the
  #on screen instructions
  def genLabelText(self, text, i):
    return OnscreenText(text = text, pos = (-1.3, .95-.05*i), fg=(1,1,1,1),
                        align = TextNode.ALeft, scale = .05)
                        
  activeConnections=[] # We'll want to keep track of these later

  def __init__(self):
    #This code puts the standard title and instruction text on screen
    self.title = OnscreenText(text="Panda3D: NCS Server window",
                              style=1, fg=(0,0,0,1),
                              pos=(0.8,-0.95), scale = .07)

    cManager = QueuedConnectionManager()
    cListener = QueuedConnectionListener(cManager, 0)
    cReader = QueuedConnectionReader(cManager, 0)
    cWriter = ConnectionWriter(cManager,0)

    activeConnections=[] # We'll want to keep track of these later

    port_address=9099 #No-other TCP/IP services are using this port
    backlog=1000 #If we ignore 1,000 connection attempts, something is wrong!
    tcpSocket = cManager.openTCPServerRendezvous(port_address,backlog)
 
    cListener.addConnection(tcpSocket)
     
    PRINT_MESSAGE = 1
    self.j = 0


    # broadcast a message to all clients
    def myNewPyDatagram(self):
        # Send a test message
        myPyDatagram = PyDatagram()
        myPyDatagram.addUint8(PRINT_MESSAGE)
        myPyDatagram.addString("Hello, world!")
        return myPyDatagram

    def tskBBC(taskdata):
        for aClient in activeConnections:
            TestDatagram = myNewPyDatagram(self)
            cWriter.send(TestDatagram,aClient)
        return Task.cont

    def tskReaderPolling(taskdata):
        if cReader.dataAvailable():
            datagram=NetDatagram()  # catch the incoming data in this instance
            # Check the return value; if we were threaded, someone else could have
            # snagged this data before we did
            if cReader.getData(datagram):
                myProcessDataFunction(datagram)
        return Task.cont

    def tskListenerPolling(taskdata):
        if cListener.newConnectionAvailable():
            rendezvous = PointerToConnection()
            netAddress = NetAddress()
            newConnection = PointerToConnection()
            if cListener.getNewConnection(rendezvous,netAddress,newConnection):
                newConnection = newConnection.p()
                activeConnections.append(newConnection) # Remember connection
                cReader.addConnection(newConnection)     # Begin reading connection
        self.genLabelText(format(len(activeConnections)),len(activeConnections))
        return Task.cont

    taskMgr.add(tskListenerPolling,"Poll the connection listener",-39)
    taskMgr.add(tskReaderPolling,"Poll the connection reader",-40)
    taskMgr.add(tskBBC,"Broadcasting")   

w=World()
run()

this is the entire code, can’t think where the writer would be destroyed or cleared. I’m new to panda though, so maybe i’ve missed something. Any advice?

    cManager = QueuedConnectionManager()
    cListener = QueuedConnectionListener(cManager, 0)
    cReader = QueuedConnectionReader(cManager, 0)
    cWriter = ConnectionWriter(cManager,0) 

These lines simply define local variables that automatically destruct as soon as the init() function returns. Since it appears that you intend for these variables to persist for the lifetime of your class object, you should store them in the class instead like this:

    self.cManager = QueuedConnectionManager()
    self.cListener = QueuedConnectionListener(self.cManager, 0)
    self.cReader = QueuedConnectionReader(self.cManager, 0)
    self.cWriter = ConnectionWriter(self.cManager,0) 

and then always reference them with the self prefix, e.g. self.cWriter instead of cWriter.

David

thanks, that did it. :blush: