Linux programming-udp socket full strategy, udpsocket
This article will summarize important knowledge points of udp socket programming in linux. This article will cover both developers and some remote knowledge points of udp socket. Do as much as possible. After reading an article, you will have a comprehensive understanding of udp socket. This article is divided into two topics, the first is the commonly used upd socket framework, and the second is some of the udp socket is not commonly used but very important knowledge points.
I. Basic udp socket programming
1. UDP programming framework
To use UDP for program development, we must first understand what UDP is? Here is a brief summary.
The user Data protocol (UDP) is a transport layer. UDP is a non-connection-oriented protocol. It does not establish a connection with the other party, but directly sends the datagram to the other party. Therefore, UDP is applicable to scenarios where the data volume transmitted at a time is small, the reliability requirement is not high, or the real-time requirement is high. Because UDP does not need to establish connections such as three-way handshakes, the communication efficiency is very high.
UDP is widely used. For example, some well-known application layer protocols (SNMP and DNS) are based on UDP. Think about it. If SNMP uses TCP, three handshakes are required for each query request, the time spent is probably intolerable to the user, as this will produce a significant lag. Therefore, UDP is a good choice for SNMP. It does not matter if packet loss occurs during the query process. We can initiate another query because there are not many packet loss situations, this is easier to accept than getting stuck in every query.
The UDP communication process is relatively simple, so it is relatively simple to build such a common UDP communication framework. The following figure shows the framework of UDP.
The preceding figure shows that the client only needs two steps (socket and sendto) to initiate a request ), the server side only needs three steps to receive messages from the client (socket, bind, recvfrom ).
2. UDP programming common functions
#include <sys/types.h> #include <sys/socket.h>int socket(int domain, int type, int protocol);
Parameter domain: used to set the domain for network communication. The socket selects the Name Purpose AF_UNIX family of information protocols based on this parameter, AF_LOCAL communication AF_INET IPv4 Internet protocols // For ipvipv6 Internet protocols // For ipvipx-Novell protocol Kernel user interface device AF_X25 ITU-T X.25/ISO-8208 protocol AF_AX25 Amateur radio AX.25 limit Access to raw atm pvc saf_appletalk AppleTalk AF_PACKET Low level packet interface AF_ALG Interface to kernel crypto API for this parameter, we only need to record AF_INET and AF_INET6.
Episode: PF_XXX and AF_XXXWhen we look at the Code related to Linux network programming, we will find that PF_XXX and AF_XXX will be mixed. What are the differences between them? The following content is taken from UNP. AF _ prefix indicates the Address Family, while PF _ prefix indicates the Protocol Family ). In history, there was an idea that a single protocol family could support multiple address families. The PF _ value could be used to create sockets, while the AF _ value was used to address structures of sockets. But in fact, protocol families that support multiple address families have never been implemented, and header files <sys/socket. h> the PF _ value defined for a given protocol is always the same as the AF _ value of this Protocol. Therefore, I prefer AF_XXX in actual programming. Parameter type (only list the three most important parameters): SOCK_STREAM Provides sequenced, reliable, two-way, connection-based byte streams. // used for TCPSOCK_DGRAM Supports datagrams (connectionless, unreliable messages ). // used for UDPSOCK_RAW Provides raw network protocol access. // RAW type, used to provide the original network access parameter protocol: Set 0 to return the value: Success: non-negative file descriptor failure:-1
#include <sys/types.h>#include <sys/socket.h>ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
The first parameter, sockfd, is the set interface file descriptor of the listening port. The second parameter, buf, is obtained through socket: The sending buffer, which is usually an array defined by the user, the array contains the third parameter len: size of the sending buffer for the data to be sent. Unit: byte fourth parameter flags: enter 0. The fifth parameter dest_addr: the structure pointing to the host address information of the received data, that is, this parameter specifies the host to which the data is sent. The sixth parameter addrlen indicates the length of the content returned by the fifth parameter: success: failed to return successfully sent Data Length:-1
#include <sys/types.h>#include <sys/socket.h>ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
The first parameter, sockfd, is the set interface file descriptor of the listening port. The second parameter, buf, is obtained through socket: The receiving buffer, which is usually an array defined by the user, the array contains the received data. The third parameter is len: the size of the receiving buffer. Unit is the fourth byte parameter flags: enter 0. The fifth parameter is src_addr: the structure that points to the host address information of the sent data, that is, we can obtain the sixth parameter addrlen from which the data is sent: indicates the length of the returned value of the content pointed to by the fifth parameter: success: failed to return the received data length:-1
#include <sys/types.h>#include <sys/socket.h>int bind(int sockfd, const struct sockaddr* my_addr, socklen_t addrlen);
The first parameter sockfd: Specifies the set interface file descriptor of the listening port. The second parameter my_addr is obtained through socket: the IP address to be bound and the return value of the struct of the third parameter addrlen: my_addr on the port: success: 0 failed:-1
#include <unistd.h>int close(int fd);
The close function is relatively simple. You only need to fill in the fd generated by the socket.
3. Build a UDP Communication Framework
Server:
1 # include <stdio. h> 2 # include <sys/types. h> 3 # include <sys/socket. h> 4 # include <netinet/in. h> 5 # include <string. h> 6 7 # define SERVER_PORT 8888 8 # define BUFF_LEN 1024 9 10 void handle_udp_msg (int fd) 11 {12 char buf [BUFF_LEN]; // receives the buffer, 1024 bytes 13 socklen_t len; 14 int count; 15 struct sockaddr_in clent_addr; // clent_addr is used to record the sender's address information 16 while (1) 17 {18 memset (buf, 0, BUFF_LEN); 19 len = sizeof (clent_ad Dr); 20 count = recvfrom (fd, buf, BUFF_LEN, 0, (struct sockaddr *) & clent_addr, & len); // recvfrom is the congestion function, if there is no data, it will always be congested 21 if (count =-1) 22 {23 printf ("recieve data fail! \ N "); 24 return; 25} 26 printf (" client: % s \ n ", buf); // print the message sent by the client 27 memset (buf, 0, BUFF_LEN); 28 sprintf (buf, "I have recieved % d bytes data! \ N ", count); // reply to client29 printf (" server: % s \ n ", buf); // print your own message to 30 sendto (fd, buf, BUFF_LEN, 0, (struct sockaddr *) & clent_addr, len); // send information to the client, note that the clent_addr struct pointer 31 32} 33} 34 35 36/* 37 server is used: 38 socket --> bind --> recvfrom --> sendto --> close39 */40 41 int main (int argc, char * argv []) 42 {43 int server_fd, ret; 44 struct sockaddr_in ser_addr; 45 46 server_fd = socket (AF_INET, SOCK_DGRAM, 0); // AF_ I NET: IPV4; SOCK_DGRAM: UDP47 if (server_fd <0) 48 {49 printf ("create socket fail! \ N "); 50 return-1; 51} 52 53 memset (& ser_addr, 0, sizeof (ser_addr); 54 ser_addr.sin_family = AF_INET; 55 rows = htonl (INADDR_ANY ); // ip address, which requires network sequence conversion. INADDR_ANY: local address 56 ser_addr.sin_port = htons (SERVER_PORT); // port number, which requires network sequence conversion 57 58 ret = bind (server_fd, (struct sockaddr *) & ser_addr, sizeof (ser_addr); 59 if (ret <0) 60 {61 printf ("socket bind fail! \ N "); 62 return-1; 63} 64 65 handle_udp_msg (server_fd); // process the received data 66 67 close (server_fd); 68 return 0; 69}
Client:
1 # include <stdio. h> 2 # include <sys/types. h> 3 # include <sys/socket. h> 4 # include <netinet/in. h> 5 # include <string. h> 6 7 # define SERVER_PORT 8888 8 # define BUFF_LEN 512 9 # define SERVER_IP "172.0.5.182" 10 11 12 void udp_msg_sender (int fd, struct sockaddr * dst) 13 {14 15 socklen_t len; 16 struct sockaddr_in src; 17 while (1) 18 {19 char buf [BUFF_LEN] = "test udp msg! \ N "; 20 len = sizeof (* dst); 21 printf (" client: % s \ n ", buf); // print your own message 22 sendto (fd, buf, BUFF_LEN, 0, dst, len); 23 memset (buf, 0, BUFF_LEN); 24 recvfrom (fd, buf, BUFF_LEN, 0, (struct sockaddr *) & src, & len); // receives information from the server 25 printf ("server: % s \ n", buf); 26 sleep (1 ); // send a message 27} 28} 29 30/* 31 client: 32 socket --> sendto --> revcfrom --> close33 */34 35 int main (int argc, char * argv []) 36 {37 int client_fd; 38 st Ruct sockaddr_in ser_addr; 39 40 client_fd = socket (AF_INET, SOCK_DGRAM, 0); 41 if (client_fd <0) 42 {43 printf ("create socket fail! \ N "); 44 return-1; 45} 46 47 memset (& ser_addr, 0, sizeof (ser_addr); 48 ser_addr.sin_family = AF_INET; 49 // region = inet_addr (SERVER_IP); 50 ser_addr.sin_addr.s_addr = htonl (INADDR_ANY); // note that the Network sequence is 51 ser_addr.sin_port = htons (SERVER_PORT ); // note network sequence conversion 52 53 udp_msg_sender (client_fd, (struct sockaddr *) & ser_addr); 54 55 close (client_fd); 56 57 return 0; 58}
The above framework is used for UDP Communication on different ports of a host. The phenomenon is as follows: we first establish the server, wait for the service, and then we establish the client to request the service. Server:
Client: It's not great for our host to communicate with ourselves. What should we do if we want to communicate with other hosts? It's easy. The above client code is commented on in line 49th, and the following line is commented out. Enter the serverip you want to communicate with in the macro definition. The phenomenon is as follows: server: client: in this way, we implement network communication between the host 172.0.5.183 and 172.0.5.182. After the General UDP framework is set up, we can use it to communicate with the specified host. If you want to learn the basic knowledge of UDP, the above knowledge is enough. If you want to continue to learn more about udp socket, you can take some time to look down.
Ii. Advanced udp socket programming
1. udp connect function
What? UDP also has conenct? Isn't connect used for TCP programming?
Yes, there is indeed a connect function in UDP network programming, but it is only used to indicate that the address of the other side is determined, and there is no other meaning.
With the above understanding, we can know that UDP sockets have the following differences:
1) unconnected UDP socket
2) connected UDP socket
For unconnected sockets, which are commonly used UDP sockets, we use sendto/recvfrom to send and receive information, the IP address and port of the target host are determined when sendto/recvfrom is called;
To call the sendto function kernel for two data packets on an unconnected UDP socket, perform the following six steps:
1) connect to the socket
2) output the first Datagram
3) disconnect the socket
4) connect to the socket
5) output the second Datagram
6) disconnect the socket
For connected UDP sockets, you must first specify the connection to the target server, and then call read/write to send and receive information, the IP address and port of the target host are determined during connect. That is to say, once the conenct succeeds, we can only send and receive information to the host.
To call the write function kernel for two datagram data packets, the connected UDP socket performs the following three steps:
1) connect to the socket
2) output the first Datagram
3) output the second Datagram
It can be seen that when the application process knows to send multiple data reports to the port number of the same destination address, it shows that the socket is more efficient.
The following describes the UDP communication framework with the connect function.
The specific framework code is no longer given, because it is similar to the code without connect above, and only one more connect function is processed. The following describes the basic steps for conenct () processing.
void udp_handler(int s, struct sockaddr* to){ char buf[1024] = "TEST UDP !"; int n = 0; connect(s, to, sizeof(*to); n = write(s, buf, 1024); read(s, buf, n);}
2. udp Packet Loss
Due to the characteristics of UDP itself, UDP may have some difficult problems compared with TCP. The first is the lack of UDP packets.
In the UDP Server Client example, if the data sent by the client is lost, the server waits until the valid data of the client comes. If the server response is discarded in the middle, the client will be blocked until the server data comes over.
The general method to prevent such permanent blocking is to set a timeout for the customer's recvfrom call. There are two possible methods:
1) Use SIGALRM to set timeout for recvfrom. First, we create a signal processing function for SIGALARM and set a 5-second timeout value through alarm before each call. If recvfrom is interrupted by our signal processing function, the message will be sent again after timeout. If data is read normally, the alarm clock will be disabled and the process will continue.
2) use select to set timeout for recvfrom
Set the fifth parameter of the select function.
3. Out-of-order udp Packets
The disordered order means that the order of sent data is inconsistent with the order of received data. For example, the order of sent data is A, B, and C, but the order of received data is: a, C, and B. The cause of this problem is that the routes used by each datagram are not the same. Some routes are smooth, while others are congested, which leads to a different order for each datagram to reach its destination. The UDP protocol does not guarantee the receipt of data packets in order.
To solve this problem, the sender adds the datagram serial number when sending data, so that the receiver can check the serial number of the datagram and queue them in order after receiving the packet, form an ordered datagram.
4. udp traffic control problems
In general, TCP has a sliding window for traffic control and congestion control. In contrast, UDP cannot be implemented due to its characteristics. When UDP receives data, it directly puts the data in the buffer zone. If the user does not copy the content in the buffer zone in time, the subsequent data will be placed in the buffer zone. When the buffer zone is full, later data will overwrite the first data and cause data loss (because the UDP buffer used by the kernel is a ring buffer ). Therefore, once the sender sends a message explosively at a certain point in time, the receiver will lose information because it is too late to receive the message.
The solution is generally to increase the UDP buffer so that the recipient's receiving capacity is greater than the sender's sending capacity.
Int n = 220*1024; // 220 kBsetsocketopt (sockfd, SOL_SOCKET, SO_RCVBUF, & n, sizeof (n ));
In this way, the receiver's receiving queue is expanded to avoid data loss. Bibliography:
UNIX Network Programming volume 1
Linux Network Programming
Embedded Linux software development from entry to entry