[Enet] Multiple Client connections

Started by
5 comments, last by ninnghazad 6 years, 10 months ago

I'm developing a client/server for a simple game I'm making, but I have no clue on how to handle several clients?

I've read a few threads here and there with the same issue, but no "solve" was posted when solved.

Here we have the server


#include <iostream>
#include <enet/enet.h>

int main(int argc, char** argv) {

	ENetAddress address;
	ENetHost* server;

	if (enet_initialize() != 0) {
		fprintf(stderr, "Failed to initialize ENet!\n");
		exit(-1);
	}

	// Bind the server to default localhost
	// Specified host address can be specified by
	// enet_address_set_host(&address, "x.x.x.x");

	address.host = ENET_HOST_ANY;

	// Bind the server to port 1234
	address.port = 8484;

	server = enet_host_create(&address /* the address to bind the server host to */,
		32      /* allow up to 32 clients and/or outgoing connections */,
		2      /* allow up to 2 channels to be used, 0 and 1 */,
		0      /* assume any amount of incoming bandwidth */,
		0      /* assume any amount of outgoing bandwidth */);
	if (server == NULL)
	{
		fprintf(stderr,
			"An error occurred while trying to create an ENet server host.\n");
		exit(EXIT_FAILURE);
	}
	else {
		std::cout << "MSC++Server has started" << std::endl << "Listening on IP: " << address.host << " Port: " << address.port << "." << std::endl;
	}

	ENetEvent event;

	while (true) {
		/* Wait up to 1000 milliseconds for an event. */
		while (enet_host_service(server, &event, 1000) > 0)
		{
			switch (event.type)
			{
			case ENET_EVENT_TYPE_CONNECT:
				printf("New connection from %x:%u.\n",
					event.peer->address.host,
					event.peer->address.port);
				/* Store any relevant client information here. */
				event.peer->data = "Client";
				break;
			case ENET_EVENT_TYPE_RECEIVE:
				printf("A packet of length %u containing %s was received from %s on channel %u.\n",
					(unsigned int)event.packet->dataLength,
					event.packet->data,
					event.peer->data,
					event.channelID);
				/* Clean up the packet now that we're done using it. */
				enet_packet_destroy(event.packet);
				break;

			case ENET_EVENT_TYPE_DISCONNECT:
				printf("%s disconnected.\n", event.peer->data);
				/* Reset the peer's client information. */
				event.peer->data = NULL;
			}
		}
	}

	atexit(enet_deinitialize);
}

This particular code especially


case ENET_EVENT_TYPE_CONNECT:
	printf("New connection from %x:%u.\n",
	event.peer->address.host,
	event.peer->address.port);
	/* Store any relevant client information here. */
	event.peer->data = "Client";
break;

I have a "peer" or client if you will, with some data.
This connection is a single connection that can be established to the server, meaning if I instance a new client, the first client will have it's data overwritten.

How do I overcome this issue?

Advertisement

I don't know ENet, but looking over the docs and your code quickly, I don't see an immediate problem, but I'm lacking some context.

You _should_ be receiving a single CONNECT message per client connection, and each one should have a unique instance of ENetPeer which you can freely modify and store data upon as in your code. You should not be receiving a DISCONNECT message between the first and second client connection if you're expecting them both to be active; are you? Are the addresses of your peer pointers difference for each CONNECT message or is the same peer being recycled?

Highly unrelated note:

    // Bind the server to port 1234
    address.port = 8484;

this is a perfect example of why comments should not just repeat what the code is (supposedly) doing. :)

Sean Middleditch – Game Systems Engineer – Join my team!

It's been about 8 years since I last used Enet, but it creates one 'peer' for every remote client that connects. I vaguely recall that you will need to remember each peer that is presented to you in this way, perhaps by copying the pointer to the peer and storing it in your program, and removing it if you get the disconnect message.

This connection is a single connection that can be established to the server, meaning if I instance a new client, the first client will have it's data overwritten.


event.peer->data = "Client";



Here is where you're supposed to allocate your own client management structure and assign it to the peer data field.
Each time Enet gets data from a particular peer, you can figure out which peer you think it is by looking at this "data" field of the peer passed into the various events.
enum Bool { True, False, FileNotFound };

Just so I'm not misunderstanding;

So I should put create the "peer" as an array and save client information into an empty index, then consistently check up on events and add updates to the client information as they do events in the game (Which I of course will be handling server side to prevent any client hacks). Am I right or nah? ^^

You don't create the peers - ENet does. Each one represents a remote connection. So you need to associate those peers with whatever other data you need to store about a remote connection. You can make the peer's 'data' pointer refer to your local player data, so that when you get an event, you can find out which player it is by looking at peer->data. You probably want a reference in the other direction as well, so that you can easily find the correct peer for each player when you want to send data via enet_peer_send.

consider https://github.com/stuntrally/stuntrally/blob/master/source/network/enet-wrapper.hpp
and store peer-ids mapped to your players/objects like Kylotan said.

This topic is closed to new replies.

Advertisement