Linux網絡編程 - UDP發送/接受數據


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM