UDP packet overwrite/overlap

Source: Internet
Author: User

For a UDP server, if several UDP clients send data to it at the same time, and the UDP server uses a single-thread serial processing method to process received UDP packets, then, when the UPD server has not processed a packet, several other clients send data at the same time, and the data is accumulated together (or overlapped ), as a result, when the UDP server receives data using the recvfrom function next time, the data actually received is a collection of Several client data (or is it out of order?

The answer is: no.

 

We can do the following experiment (this is a program in Linux ).

This is an implementation of UDP server, which blocks the receipt of client data. You will notice that after the port is successfully bound, it will sleep for 10 seconds. During this period, you can use multiple clients to send different data to the UDP server to observe the effect.

As for the client, we can directly use other tools to simulate (for example, TCP/UDP debugging Assistant) without coding.

 

// Compile the command: G ++ UDP. cpp-o udp-G

# Include <stdio. h>
# Include <sys/types. h>
# Include <sys/socket. h>
# Include <ARPA/inet. h>
# Include <string. h> // memset ()
# Include <unistd. h> // close ()

 

Void set_socket_option (Int & sock_fd );

 

Int main ()
{
Int sock_fd = 0;

If (sock_fd = socket (af_inet, sock_dgram, 0) =-1)
{
Printf ("error occured! /N ");
}
Else
{
Printf ("create socket successfully./N ");
Set_socket_option (sock_fd );

Struct sockaddr_in local_server_addr;
Local_server_addr.sin_family = af_inet;
Local_server_addr.sin_port = htons (7777 );
Local_server_addr.sin_addr.s_addr = inaddr_any;
Memset (local_server_addr.sin_zero, '/0', sizeof (local_server_addr.sin_zero ));

If (BIND (sock_fd, (struct sockaddr *) & local_server_addr, sizeof (struct sockaddr) =-1)
{
Printf ("error occured! /N ");
}
Else
{
Printf ("listen on port 7777.../N ");

 

Usleep (1000*10000 );

 

While (true)
{
Struct sockaddr_in client_addr;
Socklen_t sin_size = sizeof (client_addr );
Char Buf [1024] = "0 ";
Int ret = recvfrom (FIG, Buf, 1024, 0, (struct sockaddr *) & client_addr, & sin_size );
Printf ("Size: % d. Buffer: % s/n", RET, Buf );
}

}

Close (sock_fd );
}
Return 0;
}

 

Void set_socket_option (Int & sock_fd)
{
Int optval = 1;
Setsockopt (sock_fd, sol_socket, so_reuseaddr, & optval, sizeof (INT ));

Int recv_buf_size = 1048576; // 1 MB
Setsockopt (sock_fd, sol_socket, so_rcvbuf, (const char *) & recv_buf_size, sizeof (recv_buf_size ));

Int send_buf_size = 1048576; // 1 MB
Setsockopt (sock_fd, sol_socket, so_sndbuf, (const char *) & send_buf_size, sizeof (send_buf_size ));
}

 

 

What are the experimental results?

If there are two clients in 10 seconds of sleep, the first one first starts "AB", and the second one is followed by "12" (here: Non-hexadecimal), that is, when two clients send two bytes of data respectively, The UDP server prints the following information:

 

Size: 2. Buffer: AB

Size: 2. Buffer: 12

 

The following situations do not occur:

Size: 4. Buffer: ab12

 

 

Therefore, as mentioned above, there will be no problems of accumulation or overlap. Please feel free to use them.

 

 

 

Another problem: Some people say that the packet header generally contains message length information. I want to first receive the packet header, parse the packet length from the packet header, and then dynamically allocate memory according to the packet length, use the allocated memory to receive the remaining data. The purpose of this operation may be that the message length is unknown and may be long. If a char Buf [1024] or char Buf [2048] is used directly, it is too wasteful, I don't know if it is enough.

Let's discuss this practice as "value is not worth it ".

First, let's look at the following functions:

 

Bool recv_msg (Int & sock_fd, char * Buf, int Len)

{

Bool res = true; // return result

Struct sockaddr_in client_addr; // client's address information

Socklen_t sin_size = sizeof (client_addr );

Int ret = 0, total_size = 0;

While (total_size <Len)

{

// If can't receive specified length in a time, We shocould Continue loading ing until get enough length

Ret = recvfrom (sock_fd, BUF + total_size, len-total_size, 0, (struct sockaddr *) & client_addr, & sin_size );

If (-1 = RET | 0 = RET) // error occured or the peer has stored med an orderly shutdown

{

Break;

Res = false;

}

Total_size + = ret;

}

Return res;

}

 

The above function is an example of "receiving enough data of a specified length of bytes to collect data.

Assume that you want to first receive the message header, and the correct header is 10 bytes. If you want to receive data, use:

Char Buf [10] = "0 ";

Recv_msg (sock_fd, Buf, 10 );

 

Then you will find this hidden danger: due to an error, client a only sends 3 bytes of data for the first time (in fact, only the packet header has 10 bytes ), then the receiving function will wait until the client 1 sends data normally for the second time, and 21 bytes of data are sent (10 bytes in the packet header ), then the UDP server will continue to take out the first seven bytes of the 21 bytes, make up 10 bytes with the three bytes received for the first time, treat them as a packet header, and then parse it. This is obviously wrong, and the second correct message is also broken. Therefore, I dare not say whether it is advisable to first receive the packet header, at least I think it is meaningless. For UDP, The UDP data length in the LAN should be less than 1472 bytes, And the UDP data length on the Internet should be less than 548 bytes, please refer to the subsequent reprinted materials). Therefore, using a char Buf [2048] is enough to receive the complete message (you do not need to receive the header before receiving the subsequent part ), this overhead is not large at all. If the length of your UDP data exceeds the upper limit, consider re-designing the packet structure.

 

 

 

The last article is a good one.:

 

During UDP programming, the most common question is how many bytes are sent at a time?

Of course, there is no unique answer. The answer is different from the requirements of different systems. Here I only analyze the situation of sending chat messages like ICQ, in other cases, you may also get some help:

First, we know that TCP/IP is generally considered as a layer-4 protocol system, including the link layer, network layer, transport layer, and application layer.

UDP belongs to the transport layer. Let's look at it from the next step:

The length of an Ethernet data frame must be between-bytes, which is determined by the physical characteristics of the Ethernet.

This 1500 byte is called the MTU (maximum transmission unit) of the link layer ).

However, this does not mean that the link layer length is limited to 1500 bytes. In fact, this MTU refers to the data area of the link layer, and does not include 18 bytes at the header and tail of the link layer.

Therefore, in fact, this 1500 byte is the length limit of network layer IP datagram.

Because the IP datagram header is 20 bytes, the IP datagram data zone length is up to 1480 bytes. the 1480 byte is used to store TCP packet segments or UDP datagram from UDP.

Because the first 8 bytes of the UDP datagram, the maximum length of the UDP datagram data zone is 1472 bytes. This 1472 byte is the number of bytes that we can use. :)

 

What happens when we send UDP data greater than 1472?

This means that the IP datagram is greater than 1500 bytes and greater than MTU. At this time, the sender's IP layer needs to be split (fragmentation ).

Divide the datagram into several slices so that each slice is smaller than MTU, and the receiver IP layer needs to reorganize the datagram.

In this way, more things will be done, and more seriously, due to the characteristics of UDP, when a piece of data is lost during transmission, it is easy to receive

The datagram cannot be reorganized. This will cause the entire UDP datagram to be discarded.

 

Therefore, in a common LAN environment, it is recommended that UDP data be controlled below 1472 bytes.

 

When programming the Internet, the MTU may be set to different values on the internet router.

If we assume that the MTU is 1500 to send data, and the MTU value of a network passing through is smaller than 1500 bytes, the system will use a series of machines

To adjust the MTU value, so that the datagram can reach the destination smoothly, so that there will be many unnecessary operations.

 

Since the standard MTU value on the internet is 576 bytes, we recommend that you perform UDP programming on the Internet. we recommend that you set the UDP data length to within 548 bytes (576-8-20.

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.