Linux网络开发避坑指南:当MAC直连没有PHY时,fixed-link属性怎么配才不报错?
2026/6/1 7:16:13
| 特性 | TCP (打电话) | UDP (发短信) |
|---|---|---|
| 连接性 | 面向连接 (三次握手) | 无连接 |
| 可靠性 | 可靠 (重传、排序、校验) | 不可靠 (尽力而为) |
| 传输模式 | 字节流 (Stream) | 数据报 (Datagram) |
| Socket 类型 | SOCK_STREAM | SOCK_DGRAM |
| 核心 API | read/write | recvfrom/sendto |
| 应用场景 | 网页(HTTP)、文件传输(FTP) | 视频流、DNS、广播 |
需包含头文件:#include <netinet/in.h>
UDP 使用与 TCP 完全相同的地址结构体,没有区别。
IPv4 专用地址结构体
structsockaddr_in{shortintsin_family;// 地址族 (必须设为 AF_INET)unsignedshortintsin_port;// 端口号 (网络字节序, 使用 htons)structin_addrsin_addr;// IP 地址结构体unsignedcharsin_zero[8];// 填充字节 (置0)};structin_addr{unsignedlongs_addr;// 32位 IP 地址 (网络字节序)};需包含头文件:#include <sys/socket.h>
intsocket(intdomain,inttype,intprotocol);type: 使用SOCK_DGRAM(数据报套接字)。intbind(intsockfd,conststructsockaddr*addr,socklen_taddrlen);UDP 没有连接,不知道数据从哪来,所以接收时必须同时拿“信的数据”和“发信人的地址”。
ssize_trecvfrom(intsockfd,void*buf,size_tlen,intflags,structsockaddr*src_addr,socklen_t*addrlen);src_addr:(传出参数) 用来存储发送方的 IP 和端口信息。addrlen:(传入传出参数)src_addr的长度。NULL。UDP 没有连接,发送时必须每次都指定“发给谁”。
ssize_tsendto(intsockfd,constvoid*buf,size_tlen,intflags,conststructsockaddr*dest_addr,socklen_taddrlen);dest_addr:(传入参数)接收方的目标 IP 和端口结构体。addrlen:dest_addr的长度。listen():UDP 不需要监听,因为没有连接请求。accept():UDP 不需要接受连接。connect():UDP 可以调用,但含义不同(变为“已连接 UDP”),一般很少用。| 阶段 | 接收端 (Receiver/Server) | 发送端 (Sender/Client) |
|---|---|---|
| 1. 准备 | socket(..., SOCK_DGRAM, ...) | socket(..., SOCK_DGRAM, ...) |
| 2. 地址 | 填充sockaddr_in(本机 IP+端口) | 填充sockaddr_in(目标 IP+端口) |
| 3. 绑定 | bind()必须执行 | (通常省略,系统自动分配) |
| 4. 通信 | recvfrom()(阻塞等待数据,获取对方地址) | sendto()(直接发送,需指定目标地址) |
| 5. 回复 | sendto()(利用 recvfrom 得到的地址回复) | recvfrom()(如果需要等待回复) |
| 6. 结束 | close() | close() |
负责接收数据,打印发送者 IP,并原样回传。
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<arpa/inet.h>#include<sys/socket.h>#definePORT8888#defineBUFFER_SIZE1024intmain(){intsockfd;structsockaddr_inserv_addr,client_addr;charbuffer[BUFFER_SIZE];socklen_taddr_len=sizeof(client_addr);// 1. 创建 UDP Socketif((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0){perror("socket");exit(1);}// 2. 绑定地址 (Server 必须 Bind)memset(&serv_addr,0,sizeof(serv_addr));serv_addr.sin_family=AF_INET;serv_addr.sin_addr.s_addr=INADDR_ANY;// 监听所有网卡serv_addr.sin_port=htons(PORT);if(bind(sockfd,(structsockaddr*)&serv_addr,sizeof(serv_addr))<0){perror("bind");exit(1);}printf("[UDP Server] Listening on port %d...\n",PORT);while(1){memset(buffer,0,BUFFER_SIZE);// 3. 接收数据 (同时获取对方地址)intlen=recvfrom(sockfd,buffer,BUFFER_SIZE,0,(structsockaddr*)&client_addr,&addr_len);if(len>0){buffer[len]='\0';// 添加字符串结束符printf("Received from %s: %s\n",inet_ntoa(client_addr.sin_addr),buffer);// 4. 回复数据 (发回给 sender)sendto(sockfd,buffer,len,0,(structsockaddr*)&client_addr,addr_len);}}close(sockfd);return0;}负责发送数据到指定 IP,并等待回复。
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<arpa/inet.h>#include<sys/socket.h>#defineSERVER_PORT8888#defineSERVER_IP"192.168.7.2"// 板子IPintmain(intargc,char*argv[]){intsockfd;structsockaddr_inserv_addr;charbuffer[1024];// 1. 创建 UDP Socketif((sockfd=socket(AF_INET,SOCK_DGRAM,0))<0){perror("socket");exit(1);}// 2. 配置目标地址memset(&serv_addr,0,sizeof(serv_addr));serv_addr.sin_family=AF_INET;serv_addr.sin_port=htons(SERVER_PORT);inet_pton(AF_INET,(argc>1?argv[1]:SERVER_IP),&serv_addr.sin_addr);while(1){printf("Input > ");fgets(buffer,sizeof(buffer),stdin);// 3. 发送数据 (指定发给 serv_addr)sendto(sockfd,buffer,strlen(buffer),0,(structsockaddr*)&serv_addr,sizeof(serv_addr));// 4. 接收回复memset(buffer,0,sizeof(buffer));intlen=recvfrom(sockfd,buffer,sizeof(buffer),0,NULL,NULL);// 不关心是谁回的,填NULLif(len>0){buffer[len]='\0';printf("Echo: %s\n",buffer);}}close(sockfd);return0;}