UDP (User Datagram Protocol):用户数据报协议。

UDP 是一个不可靠的通信协议,没有重传和确认,没有有序控制,也没有拥塞控制。可以简单地理解为,在 IP 报文的基础上,UDP 增加的能力有限。

UDP编程

UDP中客户端和服务器端交互的图解:

image-20211102205255106

UDP Server :

  1. Create UDP socket.
  2. Bind the socket to server address.
  3. Wait until datagram packet arrives from client.
  4. Process the datagram packet and send a reply to client.
  5. Go back to Step 3.

UDP Client :

  1. Create UDP socket.
  2. Send message to server.
  3. Wait until response from server is received.
  4. Process reply and go back to step 2, if necessary.
  5. Close socket descriptor and exit.

主要是使用以下函数:

#include <sys/socket.h>
 
ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags, 
          struct sockaddr *from, socklen_t *addrlen); 
 
ssize_t sendto(int sockfd, const void *buff, size_t nbytes, int flags,
                const struct sockaddr *to, socklen_t *addrlen);

recvfrom的参数含义:

  1. sockfd :本地创建的套接字描述符

  2. buff :指向本地缓存的指针

  3. nbytes :最大接收数据字节

  4. flags :与 I/O 相关的参数

  5. from 和 addrlen:返回对端发送方的地址和端口等信息

返回值:实际接收的字节数。

sendto的参数意义:

  1. sockfd :本地创建的套接字描述符

  2. buff :指向本地缓存的指针

  3. nbytes :最大接收数据字节

  4. flags :与 I/O 相关的参数

  5. to 和 addrlen,表示发送的对端地址和端口等信息。

UDP例子

UDP Server:

// Server side implementation of UDP client-server model

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
  
#define PORT    8080
#define MAXLINE 1024
  
// Driver code
int main() {
    int sockfd;
    char buffer[MAXLINE];
    char sendbuffer[MAXLINE];
    struct sockaddr_in servaddr, cliaddr;
      
    // Creating socket file descriptor
    if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }
      
    memset(&servaddr, 0, sizeof(servaddr));
    memset(&cliaddr, 0, sizeof(cliaddr));
      
    // Filling server information
    servaddr.sin_family    = AF_INET; // IPv4
    servaddr.sin_addr.s_addr = INADDR_ANY;
    servaddr.sin_port = htons(PORT);
      
    // Bind the socket with the server address
    if ( bind(sockfd, (const struct sockaddr *)&servaddr, 
            sizeof(servaddr)) < 0 )
    {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
      
    int n;
    socklen_t len = (socklen_t)sizeof(cliaddr);  //len is value/resuslt
  


    for (;;) {
        n = recvfrom(sockfd, (char *)buffer, MAXLINE, 
                    MSG_WAITALL, ( struct sockaddr *) &cliaddr,
                    &len);
        buffer[n] = '\0';
        printf("Client : %s\n", buffer);
        
        sprintf(sendbuffer, "have recieve %d bytes", strlen(buffer));
        sendto(sockfd, (const char *)sendbuffer, strlen(sendbuffer), 0, 
                (const struct sockaddr *) &cliaddr, len);
        fprintf(stdout, "%s\n", sendbuffer);
    }

    return 0;
}

UDP Client:

// Client side implementation of UDP client-server model

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#define PORT     8080
#define MAXLINE 1024
  
// Driver code
int main() {
    int sockfd;
    char buffer[MAXLINE];
    char *hello = "Hello from client";
    struct sockaddr_in     servaddr;
  
    // Creating socket file descriptor
    if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }
  
    memset(&servaddr, 0, sizeof(servaddr));
      
    // Filling server information
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(PORT);
    servaddr.sin_addr.s_addr = INADDR_ANY;
      
    socklen_t len = (socklen_t)sizeof(servaddr);  //len is value/resuslt
  
    // send msg
    while (fgets(buffer, MAXLINE, stdin) != NULL) {
        int i = strlen(buffer);
        if (buffer[i - 1] == '\n') {
            buffer[i - 1] = 0;
        }
        sendto(sockfd, (const char *)buffer, strlen(buffer), 0, 
                (const struct sockaddr *) &servaddr, len);
        fprintf(stdout, "message: %s have sent.\n", buffer);
        int n = recvfrom(sockfd, (char *)buffer, MAXLINE, MSG_WAITALL, 
                    (struct sockaddr *) &servaddr, &len);
        buffer[n] = '\0';
        printf("Server : %s\n", buffer);   
    }
  
    close(sockfd);
    return 0;
}

情况1: 只运行客户端、不开启服务端

可以看见,没有响应,也发送不了数据。程序会一直阻塞在 recvfrom 上。

image-20211102210825516

情况2: 先开启服务端,再开启客户端

image-20211102210628391

image-20211102210617910

也可以使用多个UDP客户端去和UDP服务器端通信,不再细述。

总结

  • UDP 是无连接的数据报程序,和 TCP 不同,不需要三次握手建立一条连接。
  • UDP 程序通过 recvfrom 和 sendto 函数直接收发数据报报文。

reference

[1] 极客时间 · 网络编程实战 :06 | 嗨,别忘了UDP这个小兄弟

[2] UDP Server-Client implementation in C

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐