[ENet-discuss] Peer starving problem....

Nono BEZMan nonobezman at yahoo.com
Mon May 29 10:26:10 PDT 2006


Here's the test code I am using (windows based, sorry
;-)

- You can modify the following values: nbThreads,
PacketSize, ServerListenPort, ServerAddress,
EchoFullPacketSize.

- To start a server use the "-s" command line option.
To start a client, do not use any command line option.

SOURCE CODE:
-------------------------------------------------------

// EnetTest.cpp : Defines the entry point for the
console application.
//

#include "stdafx.h"
#include "enet/enet.h"
#include <Windows.h>

#include <hash_map>

// TEST CONFIG - MODIFY VALUES HERE
//
// Nb Threads = peers to use for this test
static const int nbThreads = 50;
// Size of packets sent by client to server
static const unsigned long PacketSize = 1*1024;
// Server will listen on this port
static const enet_uint16 ServerListenPort = 55555;
// Address of server
static const char *ServerAddress = "192.168.1.12";
// If true the server sends back a packet of same size
as received, else send back 1 byte only
static const bool EchoFullPacketSize = true;
// Max Random time between to consecutive sends
static const DWORD SendSleepTime = 0;
//

typedef stdext::hash_map<enet_uint32, HANDLE>		
SendEventMap;
typedef stdext::hash_map<enet_uint32,
HANDLE>::iterator	SendEventIterator;
typedef std::pair<enet_uint32, HANDLE>				
SendEventPair;

static int nbThreadsAlive = 0;
static HANDLE GlobalStart = CreateEvent(NULL, TRUE,
FALSE, NULL);
static SendEventMap SendEvents;
static bool IsSender = false;
static DWORD TransferTime = 0;
static DWORD TransferSize = 0;
CRITICAL_SECTION sendSyncSection;


DWORD WINAPI ThreadProcessService (void *param)
{
	if (param == NULL)
		return -1;

	printf("Entering ThreadProcessService\n");

	ENetHost *pHost = (ENetHost *)param;
	
	do 
	{
		ENetEvent event;
		EnterCriticalSection(&sendSyncSection);
		int enetServciceRes = enet_host_service (pHost,
&event, 20);
		LeaveCriticalSection(&sendSyncSection);

		if (enetServciceRes < 0)
		{
			printf("Exiting ThreadProcessService\n");
			return -1;
		}
		else if ((enetServciceRes == 0) || (event.type ==
ENET_EVENT_TYPE_NONE))
		{	
			//printf("Looping in ThreadProcessService\n");
			continue;
		}	

		switch (event.type)
		{
		case ENET_EVENT_TYPE_CONNECT:
			{
				nbThreadsAlive++;
				printf("Got Connection [NbAlive: %d, PeerID :
%d]\n", nbThreadsAlive, event.peer->incomingPeerID);
			}
			break;

		case ENET_EVENT_TYPE_RECEIVE:
			{
				// Got confirmation. Print out response time
				TransferSize += PacketSize;

				printf("Packet Received [NbAlive: %d, Size: %.2f
KBs, Rate: %.2f KB/sec, PeerID: %u]\n",
					nbThreadsAlive, event.packet->dataLength /
1024.0,
					 1000.0 * TransferSize / 1024.0 / (GetTickCount()
- TransferTime),
					 event.peer->incomingPeerID);

				if (IsSender == false)
				{
					EnterCriticalSection(&sendSyncSection);
					// Echo back "ack"
					ENetPacket *packet = enet_packet_create(
						NULL, (EchoFullPacketSize == true ?
event.packet->dataLength : 1),
ENET_PACKET_FLAG_RELIABLE);
					enet_peer_send(event.peer, 0, packet);
					//printf("Sent Ack packet [Size =
%d]\n",packet->dataLength;
					LeaveCriticalSection(&sendSyncSection);
				}
				else
				{
					// Wake up our thread
					SendEventIterator eventIt =
SendEvents.find(event.peer->incomingPeerID);
					if (eventIt != SendEvents.end())
					{
						SetEvent(eventIt->second);
					}
					else
					{
						printf("ThreadProcessService::Could not find
SendEvent [PeerID: %u]\n",
event.peer->incomingPeerID);
					}
				}

				enet_packet_destroy(event.packet);
			}
			break;

		case ENET_EVENT_TYPE_DISCONNECT:
			{
				nbThreadsAlive--;
				printf("Got Disconnection [NbAlive: %d, PeerID :
%d]\n", nbThreadsAlive, event.peer->incomingPeerID);
			}
			break;

		default:

			break;
		}
	} while (true);

	return 0;
}

DWORD WINAPI ThreadSend (void *param)
{
	if (param == NULL)
	{
		printf("ThreadSend::Peer is NULL - Exiting");
		return 0;
	}

	srand((unsigned)time(NULL));

	ENetPeer *pPeer = (ENetPeer *)param;
	SendEventIterator eventIt =
SendEvents.find(pPeer->incomingPeerID);
	if (eventIt == SendEvents.end())
	{
		printf("ThreadSend::Could not find SendEvent
[PeerID: %u]\n", pPeer->incomingPeerID);
	}

	HANDLE waitEvents[2];
	waitEvents[0] = eventIt->second;
	waitEvents[1] = GlobalStart;

	while (true)
	{
		WaitForMultipleObjects(2, waitEvents, FALSE,
INFINITE);

		DWORD sleepTime = SendSleepTime * rand() / RAND_MAX;
		//printf("ThreadSend::EventSet - Sleeping for %u
ms\n", sleepTime);
		Sleep(sleepTime);

		EnterCriticalSection(&sendSyncSection);

		ENetPacket *packet = enet_packet_create(NULL,
PacketSize, ENET_PACKET_FLAG_RELIABLE);

		enet_peer_send(pPeer, 0, packet);
		//printf("Sent packet [PeerID: %u, Size = %u, Res =
%d]\n", pPeer->incomingPeerID, PacketSize);

		LeaveCriticalSection(&sendSyncSection);
	}

	return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	srand((unsigned)time(NULL));

	enet_initialize();

	InitializeCriticalSection(&sendSyncSection);

	if ((argc > 1) && (strncmp ("-s", argv[1], 2) == 0)) 
	{
		IsSender = true;
		printf("Sender Mode\n");
	}
	else
	{
		printf("Receiver Mode\n");
	}

	ENetAddress localAddress;
	localAddress.host = ENET_HOST_ANY;
	if (IsSender == true)
		localAddress.port = 0;
	else
		localAddress.port = ServerListenPort;

	//ENetHost *pHost = enet_host_create(&localAddress,
500, 0, 0, 0, ENET_PEER_PING_INTERVAL);
	ENetHost *pHost = enet_host_create(&localAddress,
500, 0, 0);

	if (pHost != NULL)
	{
		// DO not care about threadid, handles...etc.. test
prog only. no cleanup here ;-)
		DWORD threadID;
		::CreateThread (NULL, 0, ThreadProcessService,
pHost, 0, &threadID);
		if (IsSender == true)
		{
			for (int i = 0; i < nbThreads; i++)
			{
				ENetAddress remoteAddress;
				enet_address_set_host(&remoteAddress,
ServerAddress);
				remoteAddress.port = ServerListenPort;
				printf("Starting Connection [Index: %d]\n", i);
				//ENetPeer *pPeer = enet_host_connect (pHost,
&remoteAddress, 1, NULL);
				ENetPeer *pPeer = enet_host_connect (pHost,
&remoteAddress, 1);
			
SendEvents.insert(SendEventPair(pPeer->incomingPeerID,
CreateEvent(NULL, FALSE, FALSE, NULL)));
				::CreateThread (NULL, 0, ThreadSend, pPeer,0,
&threadID);
			}
		}
	}
	else
	{
		printf("enet_host_create FAILED");
	}

	if (IsSender == true)
	{
		Sleep(5000);
		printf("Setting GlobalStart Event\n");
		PulseEvent(GlobalStart);
		TransferTime = GetTickCount();
	}

	getchar();

	enet_deinitialize();

	DeleteCriticalSection(&sendSyncSection);

	return 0;
}



--- Steve Williams <stevewilliams at kromestudios.com>
wrote:

> I think it's worse than that.  He was talking
> kilobytes(KB), not 
> kilobits(Kb).  At the end of his post, he states
> that they are maxing 
> out their outbound connection at 50KB.  I believe
> this will probably be 
> a 512Kbps connection.  So you're probably looking at
> 15-20 seconds to 
> send a 512KB packet per peer.
> 
> -- 
> Sly
> 
> 
> David L. Koenig wrote:
> 
> >It sounds to me like the host is running out of
> outgoing bandwidth.  
> >Most DSL connections give you about 128Kbps
> outgoing, 768Kbps to 3Mbps 
> >incoming. 512k is 4 times the outgoing max. So,
> under the best 
> >conditions you can hope to have the packet go
> through to the/from the 
> >server in four seconds. That will never happen as
> enet is going to have 
> >to break up the packets into chunks of around 1500
> bytes which is a 
> >standard MTU limit, so you lose some bytes to
> overhead.   It's so backed 
> >up with outgoing packets that it can't possibly
> send them all within the 
> >connection timeout limit. You want to try to limit
> your packet size to 
> >1500 including any overhead (UDP header overhead,
> enet overhead).
> >
> >Exactly what sort of data is it that you're trying
> to send?  Why must 
> >the packet be so large?  Do you know the
> upload/download speed provided 
> >to your server?
> >
> >-dave
> >
> >Nono BEZMan wrote:
> >  
> >
> >>Hi all,
> >>
> >>I have used enet for a while now, and we just came
> >>across this issue which we could not resolve:
> >>
> >>- Setup: we have one client talking to one server
> >>(enet_host_service every 20 ms) on a DSL
> connection.
> >>
> >>- Test1: client send packets of 512KB to server
> back
> >>to back, using only one peer. Everything goes
> fine.
> >>
> >>- Test2: client sends packets of 512KB on more
> than
> >>one peer (2-3 in general). All peers are
> disconnected
> >>after one minute or so, but one which goes on once
> it
> >>"killed" the other ones.
> >>
> >>We have also tried to send 4kB (or 2KB) packets
> with
> >>50 peers at the same time.... at the end most
> "starved
> >>to disconnection", except for a few ones (like a
> >>dozen) which then went on happily forever. The
> bigger
> >>the packet, the less peer at the end of the fight.
> >>With 1K packets we ended up with ~20 peers, with
> 2KB
> >>about 12 peers and with 4KB we had ~6 peers still
> >>going at the end.
> >>
> >>We even tried to randomize the order in which the
> >>peers where serviced in send_outgoing_commands to
> no
> >>avail.
> >>
> >>It is very puzzling to me, as enet being UDP
> based, I
> >>do not see why peers starve to death after some
> point.
> >>Sending 512KB packets back to back (and maxing our
> >>upload connection at 50kKB) works fine until we
> add a
> >>second peer....
> >>
> >>We tried Enet 1.0 (latest CVS) as well as previous
> >>versions of Enet.
> >>
> >>Anybody would have any ideas/pointer on how to
> resolve
> >>that issue?
> >>
> >>Thank you,
> >>
> >>__________________________________________________
> >>Do You Yahoo!?
> >>Tired of spam?  Yahoo! Mail has the best spam
> protection around 
> >>http://mail.yahoo.com 
> >>_______________________________________________
> >>ENet-discuss mailing list
> >>ENet-discuss at cubik.org
>
>>http://lists.cubik.org/mailman/listinfo/enet-discuss
> >>
> >>
> >>
> >>  
> >>    
> >>
> >
> >_______________________________________________
> >ENet-discuss mailing list
> >ENet-discuss at cubik.org
>
>http://lists.cubik.org/mailman/listinfo/enet-discuss
> >
> >
> >  
> >
> 
> 
> -- 
> Sly
> 
> 
> 
> This message and its attachments may contain legally
> privileged or confidential information. This message
> is intended for the use of the individual or entity
> to which it is addressed. If you are not the
> addressee indicated in this message, or the employee
> or agent responsible for delivering the message to
> the intended recipient, you may not copy or deliver
> this message or its attachments to anyone. Rather,
> you should permanently delete this message and its
> attachments and kindly notify the sender by reply
> e-mail. Any content of this message and its
> attachments, which does not relate to the official
> business of the sending company must be taken not to
> have been sent or endorsed by the sending company or
> any of its related entities. No warranty is made
> that the e-mail or attachment(s) are free from
> computer virus or other defect.
> _______________________________________________
> ENet-discuss mailing list
> ENet-discuss at cubik.org
> http://lists.cubik.org/mailman/listinfo/enet-discuss
> 


__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam
protection around 
http://mail.yahoo.com 

__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 


More information about the ENet-discuss mailing list