Socket programming practices in Linux (10) Basic UDP programming details

Source: Internet
Author: User
Tags socket error

Socket programming practices in Linux (10) Basic UDP programming details
In my two blogs, I briefly introduced and implemented the server and client programs under UDP (TCP)-based windows (basically consistent procedures in UNIX, this article continues to explore some details about UDP programming.
Is a simple UDP client/server model:

I have also implemented a simple UDP echo server/client here:



/** Practice: implement a UDP-based echo server/client ** // The server code void echoServer (int sockfd); int main () {int sockfd = socket (AF_INET, SOCK_DGRAM, 0); if (sockfd =-1) err_exit ("socket error"); struct sockaddr_in servAddr; servAddr. sin_family = AF_INET; servAddr. sin_addr.s_addr = htonl (INADDR_ANY); servAddr. sin_port = htons (8001); if (bind (sockfd, (const struct sockaddr *) & servAddr, sizeof (servAddr) =-1) err_exit ("bind error "); echoServer (sockfd);} void echoServer (int sockfd) {char buf [BUFSIZ]; optional recvBytes = 0; struct sockaddr_in clientAddr; socklen_t addrLen; while (true) {memset (buf, 0, sizeof (buf); addrLen = sizeof (clientAddr); memset (& clientAddr, 0, addrLen); recvBytes = recvfrom (sockfd, buf, sizeof (buf), 0, (struct sockaddr *) & clientAddr, & addrLen); // if recvBytes is set to 0, the peer connection is not closed because UDP is not connected if (recvBytes <0) {if (errno = EINTR) continue; else err_exit ("recvfrom error") ;}cout <buf; if (sendto (sockfd, buf, recvBytes, 0, (const struct sockaddr *) & clientAddr, addrLen) =-1) err_exit ("sendto error ");}}
/** Client code **/void echoClient (int sockfd); int main () {int sockfd = socket (AF_INET, SOCK_DGRAM, 0 ); if (sockfd =-1) err_exit ("socket error"); echoClient (sockfd); cout <"Client exiting... "<endl;} void echoClient (int sockfd) {struct sockaddr_in servAddr; servAddr. sin_family = AF_INET; servAddr. sin_addr.s_addr = inet_addr ("127.0.0.1"); servAddr. sin_port = htons (8001); char buf [BUFSIZ] = {0 }; While (fgets (buf, sizeof (buf), stdin )! = NULL) {if (sendto (sockfd, buf, strlen (buf), 0, (const struct sockaddr *) & servAddr, sizeof (servAddr) =-1) err_exit ("sendto error"); memset (buf, 0, sizeof (buf); int recvBytes = recvfrom (sockfd, buf, sizeof (buf), 0, NULL, NULL); if (recvBytes =-1) {if (errno = EINTR) continue; else err_exit ("recvfrom error");} cout <buf; memset (buf, 0, sizeof (buf ));}}
UDP is not a one-to-one communication like TCP. UDP can implement broadcast communication, and because it is connectionless, as long as you know the peer address (ip and port) can actively send data. Shut down the server, connect to the server, and perform communication.


Precautions and details for UDP programming:
1. UDP does not have a packet sticking problem because it is not stream-based transmission (message-based ).
2. UDP packets may be lost, duplicated, or out of order. The timeout processing mechanism can be used to process the loss, and the timer times out and re-transmits the data. to process the duplication and disorder, the serial number between the data packets can be maintained.
3. UDP lacks traffic control: When the buffer zone is full, UDP will overwrite the buffer zone because there is no traffic control mechanism. It can be solved by simulating the TCP Sliding Window Protocol.
4. datagram truncation: If the UDP datagram sent by the peer end is greater than the local receiving buffer, the packet may be truncated and the subsequent part will be lost (instead of being able to receive it next time as we imagine ); and if we use sendto to send "ABCD" 4 bytes, the accepted recv function receives one character every time in A loop, but the result is that we can only accept. The rest will not exist in the buffer zone, which can also form a judgment basis: the packet interface (UDP) is lost instead of the stream interface (TCP ).
5. If recvfrom is returned, 0 is returned. This does not indicate that the connection is closed because UDP is not connected.
6. ICMP Asynchronous errors(Important)
This error occurs only when one side of the server or client is opened, and this is an ICMP response error generated by the TCP/IP protocol stack. This error can be received only when recv is enabled. Because there is no notification at all, it is called asynchronous and will not be returned to the unconnected socket.
Solution: UDP calls connect
After connect is added, after sending, if the other party is not enabled, the recv will receive an ICMP error. UDP connect does not have a three-way handshake. It only maintains a message, a status, and cannot be sent to other addresses for this socket. You can do this without specifying the sendto destination address after connect, because it is already specified during connection, and you can also use the send and write methods.
Further description:


1) When UDP sends packets, only the data is copied to the sending buffer zone. If the server is unavailable, the message can be sent successfully.
2) The so-called ICMP asynchronous error refers to the process where no error occurs when a message is sent and an ICMP response is returned when the recvfrom packet is received.
3) An asynchronous error cannot return an unconnected socket. Therefore, if we call connect in the above example, we can receive the asynchronous ICMP packet;


(1) further analysis:
If the server is not started and the client sendto sends a data packet, what is the result?
The conclusion is that if sendto is returned successfully, if the client also calls recvfrom at the same time, it will always be blocked in the recvfrom function (of course time-out can be set), and tcpdump can also be seen, the server returns the ICMP port unreachable error message, but the message is not returned to the user process through the sendto and recvfrom functions. In other words, the user does not know that the server returns an ICMP error. What should we do? udp connet functions can handle this.
For udp socket to call connect, it is called a connected UDP socket. The difference between it and a non-connected UDP socket is as follows:
Use write or send instead of sendto, because the destination IP address has been specified in connect, and use read, recv, or recvmsg instead of recvfrom. Note, if the source address is not the target address of the connect connection, the socket will not be returned. This is because the kernel has helped us verify the received response; asynchronous errors caused by connected UDP sockets will be returned to the process in which they are located, which effectively solves the above problem. In addition to calling connect to determine the destination IP address and port, at the same time, the destination address is used to find the route table and determine the local address. After connect, call getsockname to obtain the address.

Conclusion: UDP clients or service processes call connect only when they use their UDP sockets to communicate with a specific unique peer. Of course, generally, UDP clients use connect more. At the same time, if connect is used, its performance will also be improved, because for sendto, before and after sending data, it needs to connect to the socket, disconnect the socket, if after connect, these two steps are saved.

 

7. Determine the UDP outbound interface:

Assume that the client has multiple IP addresses, and the remote address parameter provided by the connect/sendto function, the system selects an appropriate exit. For example, the Server IP address is 192.168.2.10, if the client's current IP addresses are 192.168.1.32 and 192.168.2.75, the IP address 192.168.2.75 is automatically selected. (The specific algorithm is skipped first ...)


An example of data packet truncation is attached:

 

Int main () {int sockfd = socket (AF_INET, SOCK_DGRAM, 0); if (sockfd =-1) err_exit ("socket error"); struct sockaddr_in servAddr; servAddr. sin_family = AF_INET; servAddr. sin_addr.s_addr = htonl (INADDR_ANY); servAddr. sin_port = htons (8001); if (bind (sockfd, (const struct sockaddr *) & servAddr, sizeof (servAddr) =-1) err_exit ("bind error "); // send data to yourself if (sendto (sockfd, "ABCDE", 5, 0, (const struct sockaddr *) & servAddr, sizeof (servAddr) =-1) err_exit ("sendto error"); for (int I = 0; I <5; ++ I) {char ch; int recvBytes = recvfrom (sockfd, & ch, 1, MSG_DONTWAIT, NULL, NULL); if (recvBytes =-1) {if (errno = EINTR) continue; else if (errno = EAGAIN) err_exit ("recvfrom error");} else cout <"char =" <ch <", recvBytes =" <recvBytes <endl ;}}

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.