network nagle?

Hi,

It seems, I have problem with my network communication.
I use TCP, and I have pu true to setnodelay.

But on my server, I sent 3000 messages, and on my client I receive only 500.

Seems to be nagle stuff… but how to avoid it?

Server:

	self.cManager = QueuedConnectionManager()
		self.cListener = QueuedConnectionListener(self.cManager, 0)
		self.cReader = QueuedConnectionReader(self.cManager, 0)
		self.cWriter = ConnectionWriter(self.cManager,0)
		
		self.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!
		self.tcpSocket = self.cManager.openTCPServerRendezvous(port_address,backlog)
		self.tcpSocket.setNoDelay(True)
		#~ self.tcpSocket = self.cManager.openUDPConnection(port_address)

		self.cListener.addConnection(self.tcpSocket)

		taskMgr.add(self.tskListenerPolling,"Poll the connection listener",-39)
		taskMgr.add(self.tskReaderPolling,"Poll the connection reader",-40)
		taskMgr.add(self.tskNetworkMessage,"Poll the messages",-38)

	def tskNetworkMessage(self,task):
		msgs=networkmessage.instance.getListOfMessage()
		if len(msgs)>0:
			for msg in msgs:
				print "network :: tskNetworkMessage " + str(msg.getNumero()) + "@" + str(task.time)
				self.cWriter.send(msg.getMsg(),msg.getConnexion())
		return Task.cont

Client:

port_address=9099  # same for client and server
		self.cManager = QueuedConnectionManager()
		self.cReader = QueuedConnectionReader(self.cManager, 0)
		self.cWriter = ConnectionWriter(self.cManager,0)
	# a valid server URL. You can also use a DNS name
	# if the server has one, such as "localhost" or "panda3d.org"
		ip_address="127.0.0.1"
		#~ ip_address="192.168.0.254"

	# how long until we give up trying to reach the server?
		timeout_in_miliseconds=3000  # 3 seconds
		
		self.myConnection=self.cManager.openTCPClientConnection(ip_address,port_address,timeout_in_miliseconds)
		#~ self.myConnection=self.cManager.openUDPClientConnection(ip_address,port_address,timeout_in_miliseconds)
		if self.myConnection:
			self.cReader.addConnection(self.myConnection)  # receive messages from server
			self.myConnection.setNoDelay(True)
		
		#~ taskMgr.add(self.tskListenerPolling,"Poll the connection listener",-39)
		taskMgr.add(self.tskReaderPolling,"Poll the connection reader",-40)  

def tskReaderPolling(self,taskdata):
		if self.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 self.cReader.getData(datagram):
				self.myProcessDataFunction(datagram)
		return Task.cont
		
	def myProcessDataFunction(self,netDatagram):
		myIterator=PyDatagramIterator(netDatagram)
		connexion=netDatagram.getConnection()
		msgID=myIterator.getUint8()
		msg=myIterator.getString()		
		msgtab=msg.split("@")
		temp=message(msgID,msgtab[1])
		print "msg received : "+ str(msgtab)
		self.listOfMessage.append(temp)

You have to check the return value of cWriter.send(), since it will return False if it cannot send the message immediately. Or pass True as the third parameter to tell it to block until there is space available in the queue.

To specifically disable the TCP/IP Nagle algorithm, you can call connection.setNoDelay(True). But I’m not sure that this is the source of your problem.

David

No it should not. Because TCP is reliable. So with Nagle enabled it will only need more time (until the internal timeout is reached which normally around 100-200 ms). But it is possible that your packet got batched (which is the basic idea and goal of the nagle-ack stuff).
So how do you define a “packet”? Successful calls of recv?

On which connection? The connection you create to listen the connection?

self.tcpSocket = self.cManager.openTCPServerRendezvous(port_address,backlog) 

Each connection received?

if self.cListener.getNewConnection(rendezvous,netAddress,newConnection):
				newConnection = newConnection.p()
				self.activeConnections.append(newConnection) # Remember connection
				self.cReader.addConnection(newConnection)     # Begin reading connection

I don’t understand your question… can you develop? or give some example?

Each connection as you open it. The listener connection means nothing. But as I and Nox pointed out, this is unlikely to be the source of your problem. You should try my first suggestion:

With the code you posted, it’s likely that you’re not actually sending all 3000 messages to the client, until you fix the above problem.

With TCP, all messages you do send successfully are guaranteed to be delivered.

David

Weird… ok I will test the two suggestions.

Thank you!

I put the setNoDelay(True) on new connection, and I test the value of send return, and it is always 1.
So I have no problem to send it seems.

But I got an idea of the problem…

on server side, on one taskTime I can send 1-10 messages


	def tskNetworkMessage(self,task):
		msgs=networkmessage.instance.getListOfMessage()
		if len(msgs)>0:
			for msg in msgs:
				print "network :: tskNetworkMessage " + str(msg.getNumero()) + "@" + str(task.time)
				ret=self.cWriter.send(msg.getMsg(),msg.getConnexion(),True)
				print "network :: tskNetworkMessage " + str(ret)
return Task.cont

On my client, it seems I treat one message per tasktime:

def tskReaderPolling(self,taskdata):
		if self.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 self.cReader.getData(datagram):
				self.myProcessDataFunction(datagram)
				print "received at " + str(taskdata.time)
		return Task.cont

Is it insane if I replace self.reader.dataAvailable by:

while(self.reader.dataAvailable)?

If I do this, will I have the risk that the loop will treat data always, and will never end the loop to go to the next tasktime, and overload the other task?

Yes, you have that risk. It depends on how much time you spend processing each message, of course, vs. how fast the messages arrive.

But if you can’t process the messages faster than they arrive, you will have problems no matter which approach you take.

David

In fact, I am just add the message to a list, and other process search in this list the messages it needs.

So, there is zero time affected to process the message, so I think the risk is minimal.

Thank you anyway