UDP features
no connection , data transmission service for datagram (message-based, non-sticky);
Unreliable (May drop packets, disorderly order, repeat), but generally the UDP is more efficient;
UDP client/server model
udp-api use
#include <sys/types.h> #include <sys/socket.h>ssize_t recvfrom (int sockfd, void *buf, size_t len, int flags,< C3/>struct sockaddr *src_addr, socklen_t *addrlen); ssize_t sendto (int sockfd, const void *buf, size_t len, int flags, const struct SOCKADDR *dest_addr, socklen_t Addrlen);
/** Practice: Implement a UDP-based echo Echo server/client**///server-end 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]; ssize_t 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, &add Rlen); If recvbytes=0, does not mean that the peer connection is 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-Side 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, (cons t 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)); }}
Practice Analysis: Compile and run server, in two terminals each open a client and server interaction, you can see the server has the ability of concurrent services. Use <Ctrl+C> to close the server, and then run server, at which point the client can also contact the server. Compared with the result of the previous TCP program, we can realize the meaning of no connection. In the case of the UDP protocol, the boundary between server and client is more blurred, as long as the peer address (IP and port) is known to be able to proactively send data.
UDP Programming Considerations
1.UDP messages may be lost (retransmission over time), duplicated, scrambled (maintenance of a sequence number)
2.UDP Lack of flow control : When the buffer is full, the buffer is overwritten because UDP has no traffic control mechanism.
3. UDP packet Truncation : If the UDP datagram sent to the end is larger than the local receive buffer, the message may be truncated and the latter part will be lost (rather than being able to receive the next time as we imagined).
4.recvfrom can return 0, does not mean that the connection is closed, because UDP is not connected, on behalf of the sending side did not send any data [sendto can send data 0 packets (containing only UDP+IP header 40B)].
5.ICMP Async Error
Observe the phenomenon: using the example above, close the UDP server, start the client, accept the data from the keyboard, and then send the data. If the flags flag in Recvfrom is 0 and the client does not call connect, the UDP clients are blocked in the Recvfrom location (see test Code 3);
Description:
1) When UDP sends the paper, only copy the data to the send buffer. If the server is not up, it can be sent successfully .
2) The so-called ICMP asynchronous error refers to: When the message is sent, there is no error, when receiving the message recvfrom, the return to the ICMP reply.
3) Asynchronous error, unable to return an unbound socket, so if the above example we call connect, it is possible to receive the asynchronous ICMP packet;
6.UDP Call Connect
1)UDP call Connet, and no three handshake, just maintain a (and peer) state information , so we can see even if the server is not turned on, Connect on the client side can still be returned correctly! (Test code like test code 2)
2) One but call Connect, send can use Send/write, receive can use Recv/read function (see Test Code 3)
Determination of the 7.UDP outgoing interface:
Assuming that the client has multiple IP addresses, the parameters of the remote address provided by the CONNECT/SENDTO function, the system chooses an appropriate exit, such as the server's IP is 192.168.2.10, and the client's IP now has 192.168.1.32 and 192.168.2.75 will automatically choose 192.168.2.75 this IP to go out.
/** Test 1: Test note point 3, UDP packet truncation, recvfrom return-1, errno value is eagain**/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 yourself data 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; }}
/** Test 2: The code of the client-side echoclient function is modified as follows, note that the program is executed when the server side is not open **/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); UDP Client Side calls Connect if (connect (sockfd, const struct sockaddr *) &servaddr, sizeof (servaddr)) = = 1) Err _exit ("Connect error"); Char Buf[bufsiz] = {0}; while (Fgets (buf, sizeof (BUF), stdin)! = NULL) {if (SendTo (SOCKFD, buf, strlen (BUF), 0, (cons t 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) err_exit ("Recvfrom error"); cout << buf; memset (buf, 0, sizeof (BUF)); }}
/** test the 3:client end calls send after calling Connect, instead of send**/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); UDP Client side calls connect if (Connect (sockfd, const struct sockaddr *) &servaddr, sizeof (servaddr)) = = 1) err _exit ("Connect error"); Char Buf[bufsiz] = {0}; while (Fgets (buf, sizeof (BUF), stdin)! = NULL) { if (send (SOCKFD, buf, strlen (BUF), 0) = =-1) Err_exit ("Sen D error "); memset (buf, 0, sizeof (BUF)); int recvbytes = recv (sockfd, buf, sizeof (BUF), 0); if (recvbytes = =-1) err_exit ("recv error"); cout << buf; memset (buf, 0, sizeof (BUF));} }
Socket Programming Practice (--UDP) Basics of programming