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。
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.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;
}
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
./server &netstat -anup | grep 8888 應見 udp 0 0 0.0.0.0:8888./client 127.0.0.1 8888Ctrl+D 結束 Client。recvfrom 的 addrlen 必須初始化為結構大小,函數返回時會更新實際長度。connect() 後可簡化為 read/write,但仍屬無連線協議,僅固定預設目的地。