Klimczak.Jan Posted February 4, 2018 Share Posted February 4, 2018 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
fox Posted February 6, 2018 Share Posted February 6, 2018 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! 1 Link to comment
Klimczak.Jan Posted February 6, 2018 Author Share Posted February 6, 2018 (edited) 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 February 7, 2018 by Klimczak.Jan Link to comment
fox Posted February 8, 2018 Share Posted February 8, 2018 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! 1 Link to comment
Klimczak.Jan Posted February 8, 2018 Author Share Posted February 8, 2018 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
Recommended Posts