Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Send any type of data over UDP

Tags:

c++

udp

I tried searching everywhere but no luck. Here is my problem:

I have a UDP socket, which can send data to any IP address through any port (tested and confirmed working).

I read many tutorials, but they were all manipulating char*[], they did not specify how to decrypt it.

What I would like to do (pseudo code):

Client:

Class my_class;
send (..., my_class, sizeof(my_class),...)

Server:

receive (sender, buffer, sizeof (buffer))
and do something like
Class my_class = (Class) buffer

So I my server can analyze the content of the buffer.

But I'm lost with pointers, and all I can send is char*[], so I don't know how to convert back and forth.

like image 678
Stephane Avatar asked May 04 '12 14:05

Stephane


People also ask

Can you transfer files using UDP?

UDP, which stands for User Datagram Protocol, is a method used to transfer large files across the Internet. TCP, or Transmission Control Protocol, is the more widely known and used protocol for file transmission, however, falls short in comparison when it comes to transferring large files at fast speeds.

Can TCP send data over UDP?

In some cases like cellular transmission, the good old TCP/UDP packet transmission will work just fine.

How does UDP transfer data?

UDP works by gathering data in a UDP packet and adding its own header information to the packet. This data consists of the source and destination ports on which to communicate, the packet length and a checksum. After UDP packets are encapsulated in an IP packet, they're sent off to their destinations.

Can you send and receive on same UDP port?

Once connected, a TCP socket can only send and receive to/from the remote machine. This means that you'll need one TCP socket for each client in your application. UDP is not connection-based, you can send and receive to/from anyone at any time with the same socket.


2 Answers

You can't just "send" your class. You have to send a representation of the data in your class. And sending a pointer to your class won't work either. When another application on the network receives your pointer, it will be meaningless to them.

Consider this:

class Data
{
  std::string  name_;
  unsigned value_;
} data;

You can't just "send the class" down the wire. If you tried to do something like this:

send(&data, sizeof(data));

...you will end up sending nonsense to the downstream client. value_ might be received properly, but name_ surely won't. This is because a std::string object consists of much more than just the characters that make up the string. There are also counters, pointers to data buffers, and who knows what else. The characters themselves are probably not even going to be in the memory space indicated by (&data, &data[sizeof(data)]) -- those characters will be somewhere else entirely. So with the send psudocude above, not only do you send a bunch of stuff that the client can't understand, very often you don't even send what they can understand.

Enter serialization. Serialization simply means creating a representation of your data object that can be stored, saved or sent someplace, and reassembled later. You decide what shape this serialization will take. In the case of data above, we might decide to serialize like this:

NNNNCCCCCCCC...VVVV

where each character is 1 byte, and:

  1. N is a 4 character integer, and is the number of characters in name_ in ASCII representation
  2. C is N bytes, with each one being one character in name_
  3. V is a 4 character unsigned integer, and is the value in value_ in ASCII representation

One way to serialize & send data above might be something like this (warning: not production quality, untested):

stringstream ss;
ss 
  << setw(4) << setfill('0') << right << data.name_.length() << setw(0)
  << data.name_
  << setw(4) << data.value_;

  string buf = ss.str();

  send(buf.c_str(), buf.length());

Now, instead of trying to send data, we're sending a character string that represents data. If data was created like this:

data.name_ = "foo";
data.value_ = 42;

...then the string that gets sent down the socket will be:

0003foo0042

This can be received by the client and reassembled in to a new Data object on the client side that mimics what you have on the server side.

The mapping we used above -- the NNNNCCCCCCCC...VVVV -- must be understood by both sides. This is often referred to as a communications protocol.

There are countless protocols and serialization methods used across all application domains. They range from the uber simplistic, like the one I outlined above, to highly compressed and complex, like FIX/FAST. Many libraries provide serialization capabilities that meet the needs of a wide range of applications. Boost.Serialization comes to mind, and I'd suggest you look in to that.

There is much more to this that I've glossed over here. Things like Endianness, security, session control... If you are going to be doing any significant network programming, either on the client side or the server side, you've got quite a bit of learning ahead of you.

like image 155
John Dibling Avatar answered Oct 04 '22 03:10

John Dibling


You need to serialize your class. This converts to a binary representation, which you can then put inside a char*[] data type and send. char*[] is really just holding bytes to send, so you need to convert your class into bytes. When it arrives on the other side, you will need to deserialize it: convert it from an array of bytes back to an object.

like image 35
Oleksi Avatar answered Oct 04 '22 02:10

Oleksi