Jump to content

Send message to specified client by Socket class


photo

Recommended Posts

Hi,

It is possible to send data to specified client by Socket class (via UDP: SOCKET_DGRAM)?

I have server and connected to it 5 clients and I want to send just one message for specified client for e.g. numbered 3. 

Do I can do it with Socket class or I should write my own implementation ?

Thank's in advance,

Jan

 

Link to comment

Hi Jan!

Yes, it is possible!

The simplest way would be to create a server that broadcasts UDP messages having the receiving client's ID in the beginning. Then each client checks client's ID of the received message and processes it in case if the message is addressed to it.

Below is a simplified example, just to illustrate the idea:


// UDP port to be used
const int UDP_PORT = 8889;
// sizes of sending and receiving buffers
const int RECV_SIZE = 7;
const int SEND_SIZE = 7;

// Server  socket
class ServerSocket {
public:
	ServerSocket() {
		// Opening the socket on a given port (broadcast address: 127.255.255.255), setting send size, binding the socket to the host's address and setting it as a nonblocking one
		socket = Unigine::Socket::create(Unigine::Socket::SOCKET_DGRAM);
		socket->open("127.255.255.255", UDP_PORT);
		socket->send(SEND_SIZE);
		socket->broadcast();
		socket->nonblock();
	}

	~ServerSocket() {
		socket->close();
		socket.destroy();
	}
	// sending message to a certain client
	void send_message(int client_num, const char *message)
	{
		Unigine::BlobPtr blob = Unigine::Blob::create();
		blob->clear();
		blob->writeShort(client_num);
		blob->write(message, strlen(message));
		int size = blob->getSize();
		socket->write(blob->getData(), blob->getSize());
		blob.clear();
	}
private:
	Unigine::SocketPtr socket;
};

// Client socket
class ClientSocket {

public:
	ClientSocket() {
		// Opening the socket on a given port, setting receive size, binding the socket to the host's address and setting it as a nonblocking one
		socket = Unigine::Socket::create(Unigine::Socket::SOCKET_DGRAM);
		socket->open(UDP_PORT);
		socket->recv(RECV_SIZE);
		socket->bind();
		socket->nonblock();

	}
	~ClientSocket() {
		socket->close();
		socket.destroy();
	}
	void setID(int num)
	{
		// setting client's ID
		id = num;
	}

	int update() {

		Unigine::BlobPtr temp_blob = Unigine::Blob::create();
		temp_blob->clear();
		// reading data from the socket
		socket->readStream(temp_blob->getStream(), RECV_SIZE);
		if (temp_blob->getSize() > 0){
			temp_blob->seekSet(0);
			// getting client's ID
			int num_client = temp_blob->readShort();
			// checking if the received message is addressed to this particular client and processing it
			if (num_client == id){
				Unigine::Log::message("\nClient[%d] - OPERATION_CODE: %s", id, temp_blob->readLine().get());
			}
		}
		return 1;
	}
private:
	Unigine::SocketPtr socket;
	int id = 0;
};

Then, you can create your server and 5 clients and send your messages:

// declaring server and clients
ServerSocket server_socket;
ClientSocket clients[5];

/*...*/

// setting IDs
for (int i = 0; i < 5; i++)
	clients[i].setID(i);

/*...*/

// sending a message to client 2
server_socket.send_message(2, "SWT");

// sending a message to client 5
server_socket.send_message(5, "F");

 

Thanks!

  • Like 1
Link to comment
On 6.02.2018 at 3:46 AM, fox said:

Hi Jan!

Yes, it is possible!

The simplest way would be to create a server that broadcasts UDP messages having the receiving client's ID in the beginning. Then each client checks client's ID of the received message and processes it in case if the message is addressed to it.

Below is a simplified example, just to illustrate the idea:



// UDP port to be used
const int UDP_PORT = 8889;
// sizes of sending and receiving buffers
const int RECV_SIZE = 7;
const int SEND_SIZE = 7;

// Server  socket
class ServerSocket {
public:
	ServerSocket() {
		// Opening the socket on a given port (broadcast address: 127.255.255.255), setting send size, binding the socket to the host's address and setting it as a nonblocking one
		socket = Unigine::Socket::create(Unigine::Socket::SOCKET_DGRAM);
		socket->open("127.255.255.255", UDP_PORT);
		socket->send(SEND_SIZE);
		socket->broadcast();
		socket->nonblock();
	}

	~ServerSocket() {
		socket->close();
		socket.destroy();
	}
	// sending message to a certain client
	void send_message(int client_num, const char *message)
	{
		Unigine::BlobPtr blob = Unigine::Blob::create();
		blob->clear();
		blob->writeShort(client_num);
		blob->write(message, strlen(message));
		int size = blob->getSize();
		socket->write(blob->getData(), blob->getSize());
		blob.clear();
	}
private:
	Unigine::SocketPtr socket;
};

// Client socket
class ClientSocket {

public:
	ClientSocket() {
		// Opening the socket on a given port, setting receive size, binding the socket to the host's address and setting it as a nonblocking one
		socket = Unigine::Socket::create(Unigine::Socket::SOCKET_DGRAM);
		socket->open(UDP_PORT);
		socket->recv(RECV_SIZE);
		socket->bind();
		socket->nonblock();

	}
	~ClientSocket() {
		socket->close();
		socket.destroy();
	}
	void setID(int num)
	{
		// setting client's ID
		id = num;
	}

	int update() {

		Unigine::BlobPtr temp_blob = Unigine::Blob::create();
		temp_blob->clear();
		// reading data from the socket
		socket->readStream(temp_blob->getStream(), RECV_SIZE);
		if (temp_blob->getSize() > 0){
			temp_blob->seekSet(0);
			// getting client's ID
			int num_client = temp_blob->readShort();
			// checking if the received message is addressed to this particular client and processing it
			if (num_client == id){
				Unigine::Log::message("\nClient[%d] - OPERATION_CODE: %s", id, temp_blob->readLine().get());
			}
		}
		return 1;
	}
private:
	Unigine::SocketPtr socket;
	int id = 0;
};

Then, you can create your server and 5 clients and send your messages:


// declaring server and clients
ServerSocket server_socket;
ClientSocket clients[5];

/*...*/

// setting IDs
for (int i = 0; i < 5; i++)
	clients[i].setID(i);

/*...*/

// sending a message to client 2
server_socket.send_message(2, "SWT");

// sending a message to client 5
server_socket.send_message(5, "F");

 

Thanks!

Thank You Fox! That's great working example :) :) You could even add this to Samples.

 

I am also curious if is possible to send stream data just directly to one selected client as for e.g. winsock sendto method (link) ?. Or disconnect one selected ?

Do broadcast will work over Internet (between server with static IP and clients with dynamic ones, so may be hidden by NAT) ? As I know the messages will be not broadcasted against router and I don't want to use port forwarding and any other tunneling method to connect clients with server (I just want that client connect to stored IP address of server and then server will communicate them back at discovered route).  

I am not know FileDescriptor yet ;). How can I use it ? And what can I do with it ? Maybe this will answer me for my questions ? 

Do I wright that Unigine Socket class based on Windows platform is Winsock 2 implementation ? If so, then I can cast FD to windows socket pointer ?  

Thanks in advance :)

Edited by Klimczak.Jan
Link to comment

1. Do I wright that Unigine Socket class based on Windows platform is Winsock 2 implementation ? If so, then I can cast FD to windows socket pointer ?  
Yes, You're right!

Unigine::Socket uniginesocket;
SOCKET s = uniginesocket->getFD();

2. I am not know FileDescriptor yet ;). How can I use it ? And what can I do with it ? Maybe this will answer me for my questions ?
FD represents a "windows socket pointer". So You can use it as You would normally do with a WinSock 2 SOCKET.

3. I am also curious if is possible to send stream data just directly to one selected client as for e.g. winsock sendto method  ?. Or disconnect one selected ?
It is possible, but You'll have to write Your own implementation. You can use the sendto() method after getting an FD:

    SOCKET SendSocket = uniginesocket->getFD();

    sockaddr_in RecvAddr;
    unsigned short Port = 8889;

    char SendBuf[1024];
    int BufLen = 1024;

    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(Port);
    RecvAddr.sin_addr.s_addr = inet_addr("192.168.1.1");
    sendto(SendSocket, SendBuf, BufLen, 0, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));

UDP is a connectionless protocol, so you can't disconnect a client, just stop sending packets to it.

Do broadcast will work over Internet (between server with static IP and clients with dynamic ones, so may be hidden by NAT).

Broadcasting over the Internet won't work, direct connections might work... Perhaps You'll find something useful here:

https://gafferongames.com/post/virtual_connection_over_udp/

Thanks!

  • Like 1
Link to comment
5 hours ago, fox said:

1. Do I wright that Unigine Socket class based on Windows platform is Winsock 2 implementation ? If so, then I can cast FD to windows socket pointer ?  
Yes, You're right!


Unigine::Socket uniginesocket;
SOCKET s = uniginesocket->getFD();

2. I am not know FileDescriptor yet ;). How can I use it ? And what can I do with it ? Maybe this will answer me for my questions ?
FD represents a "windows socket pointer". So You can use it as You would normally do with a WinSock 2 SOCKET.

3. I am also curious if is possible to send stream data just directly to one selected client as for e.g. winsock sendto method  ?. Or disconnect one selected ?
It is possible, but You'll have to write Your own implementation. You can use the sendto() method after getting an FD:


    SOCKET SendSocket = uniginesocket->getFD();

    sockaddr_in RecvAddr;
    unsigned short Port = 8889;

    char SendBuf[1024];
    int BufLen = 1024;

    RecvAddr.sin_family = AF_INET;
    RecvAddr.sin_port = htons(Port);
    RecvAddr.sin_addr.s_addr = inet_addr("192.168.1.1");
    sendto(SendSocket, SendBuf, BufLen, 0, (SOCKADDR *) & RecvAddr, sizeof (RecvAddr));

UDP is a connectionless protocol, so you can't disconnect a client, just stop sending packets to it.

Do broadcast will work over Internet (between server with static IP and clients with dynamic ones, so may be hidden by NAT).

Broadcasting over the Internet won't work, direct connections might work... Perhaps You'll find something useful here:

https://gafferongames.com/post/virtual_connection_over_udp/

Thanks!

That's what I needs :) I will try to do my implementation with it.

I prefer to use all what I can from Unigine SDK and just add a little what I am missing instead to rewrite it at all.

With your help I will do that (networking is my week side) :) Fox, thanks again!

Link to comment
×
×
  • Create New...