Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux UDP 網路程式設計:recvfrom 與 sendto 實作範例

編輯:Linux 教學

UDP 無連線特性與核心 API

UDP(User Datagram Protocol)不建立連線,每個資料報獨立路由。核心提供兩個系統呼叫:

  • ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, 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):指定目的位址發送資料。

若不關心來源/目的,對應參數可傳 NULL。

完整 Echo Server / Client 範例

Server 端 (server.c)

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

#define PORT 8888
#define MAX_MSG 1024

int main() {
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) { perror("socket"); exit(1); }

    struct sockaddr_in servaddr, cliaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(PORT);

    if (bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
        perror("bind"); exit(1);
    }
    printf("UDP Server listening on port %d...\n", PORT);

    socklen_t len = sizeof(cliaddr);
    char buf[MAX_MSG];
    while (1) {
        int n = recvfrom(sockfd, buf, MAX_MSG, 0, (struct sockaddr*)&cliaddr, &len);
        if (n < 0) { perror("recvfrom"); continue; }
        buf[n] = '\0';
        printf("Received from %s:%d: %s\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port), buf);
        sendto(sockfd, buf, n, 0, (struct sockaddr*)&cliaddr, len);
    }
    close(sockfd);
    return 0;
}

Client 端 (client.c)

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

#define MAX_BUF 1024

int main(int argc, char **argv) {
    if (argc != 3) {
        fprintf(stderr, "Usage: %s  \n", argv[0]);
        exit(1);
    }

    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) { perror("socket"); exit(1); }

    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(atoi(argv[2]));
    if (inet_aton(argv[1], &servaddr.sin_addr) == 0) {
        fprintf(stderr, "Invalid IP address\n"); exit(1);
    }

    // 可選:connect() 綁定預設目的地,後續可用 read/write
    if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
        perror("connect"); exit(1);
    }

    char buf[MAX_BUF];
    while (fgets(buf, MAX_BUF, stdin)) {
        size_t len = strlen(buf);
        if (send(sockfd, buf, len, 0) < 0) { perror("send"); break; }

        int n = recv(sockfd, buf, MAX_BUF, 0);
        if (n <= 0) { perror("recv"); break; }
        buf[n] = '\0';
        printf("Echo: %s", buf);
    }
    close(sockfd);
    return 0;
}

Makefile

all: server client
server: server.c
	gcc -o server server.c
client: client.c
	gcc -o client client.c
clean:
	rm -f server client core

執行與驗證

  1. 啟動 Server:./server &
  2. 檢查埠監聽:netstat -anup | grep 8888 應見 udp 0 0 0.0.0.0:8888
  3. 啟動 Client:./client 127.0.0.1 8888
  4. 鍵入文字,Server 將原封不動回傳;輸入 Ctrl+D 結束 Client。

關鍵點提醒

  • UDP 不保證送達、不重序、不流控,應用層需自行處理重傳與超時。
  • recvfrom 的 addrlen 必須初始化為結構大小,函數返回時會更新實際長度。
  • Client 使用 connect() 後可簡化為 read/write,但仍屬無連線協議,僅固定預設目的地。
Copyright © Windows教程網 All Rights Reserved