当前位置: 首页 > news >正文

UDP原理和极简socket编程demo

一、通信基石:端口和五元组

什么是五元组

在TCP/IP协议中,标识一个唯一的通信连接需要五个元素:

  • 源IP
  • 源端口号
  • 目的IP
  • 目的端口号
  • 协议号(如TCP或UDP)

在Linux中,可以使用netstat -n命令查看这些信息

端口号划分

  • 知名端口号0~1023
  • 私有端口号:1024~65535

一个进程可以绑定多个端口号吗?

可以,一个进程可以创建多个Socket文件描述符,每个Socket都可以绑定一个独立的端口

一个端口号可以被多个进程绑定吗?

默认不行,有特例

  • 若进程A绑定了8080,进程B再绑定8080,OS会抛出”地址被使用“错误
  • 特例:如果使用了setsockopt设置了SO_REUSEADDRSO_REUSEPORT

二、 UDP报文结构

UDP协议头格式

UDP头部固定8个字节,协议就是结构体:

在内核视角下:

structudphdr{uint16_tsource;// 16位源端口号uint16_tdest;// 16位目的端口号uint16_tlen;// UDP长度(报头+数据)uint16_tcheck;// 校验和};
字段长度作用
源端口号16位标识发送进程
目的端口号16位标识接收进程 (用于分用)
UDP长度16位表示整个数据报(首部+数据)的最大长度
UDP校验和16位如果校验和出错,数据会被直接丢弃

怎么解包?

OS读取报文的前8个字节,剩下的内容就是有效载荷

怎么分用?

基于16位目的端口号,内核根据这个端口号,把数据推送绑定了该端口的应用层进程的接收缓冲区当中

UDP的痛点:16位长度的限制

UDP长度只有16位,则为216−1=655352^{16} - 1= 655352161=65535,这意味着一个UDP包(包含头部)最大只能是64KB

如果UDP要上传大于64KB的数据怎么办?

必须在应用层手动分包,程序员自己实现把大文件切成小块,发送过去,再接收拼装

UDP特点

  • 面向数据报

    • 定义:应用层交给UDP多长的报文,UDP原样转发,不拆分,也不合并
  • 缓冲区机制:

    • 发送缓冲区:UDP没有真正意义上的缓冲区,调用sendto会直接交给内核,内核拷贝给网卡驱动

    • 接收缓冲区:UDP有接收缓冲区

      • 接收缓冲区不能保证收到数据包的顺序和发送顺序一致
      • 丢包:如果接收缓冲区满了,新到达的数据就会直接被丢弃
    • 怎么做到数据转发?

      应用层调用sendto发数据时:

      1. 数据从应用层拷贝到传输层
      2. 内核在数据前添加UDP报头
      3. 继续交给下层处理

总结:

  • 面向数据报:上层给我什么样,我就加个报头,不做任何处理向下层交付
  • 无连接:知道对方的IP和端口号就直接传输,无需连接
  • 不可靠:没有确认机制,没有重传机制,如果因为网络故障该段无法发到对方, UDP协议也不会给应用层返回任何错误信息

三、 UDP Socket编程demo

服务端

#include<iostream>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include<cstring>#include<unistd.h>#definePORT8080#defineBUFFER_SIZE1024intmain(){// 1. 创建套接字 socket// AF_INET: IPv4// SOCK_DGRAM: UDP数据报类型// 0: 默认intsockfd=::socket(AF_INET,SOCK_DGRAM,0);if(sockfd<0){std::cerr<<"socket create err"<<errno<<std::endl;return-1;}// 2. 填充服务器地址结构体structsockaddr_inserver_addr;memset(&server_addr,0,sizeof(server_addr));// 清零,防止垃圾数据server_addr.sin_family=AF_INET;server_addr.sin_addr.s_addr=INADDR_ANY;// 接收任意网卡的连接server_addr.sin_port=::htons(PORT);// 端口转网络字节序// 3. 绑定 bind// 必须绑定,否则客户端不知道发给谁if(::bind(sockfd,(structsockaddr*)&server_addr,sizeof(server_addr))<0){std::cerr<<"bind err"<<errno<<std::endl;return-1;}std::cout<<"UDP Server is running on port "<<PORT<<"..."<<std::endl;charbuffer[BUFFER_SIZE];structsockaddr_inclient_addr;// 必须保护客户端的信息socklen_t len=sizeof(client_addr);// 必须初始化为结构体的大小while(1){// 4. 接收数据 recvfrom// 最后两个参数是输出型参数,内核会把"谁发的"填进去intn=::recvfrom(sockfd,(char*)buffer,BUFFER_SIZE,0,(structsockaddr*)&client_addr,&len);buffer[n]='\0';std::cout<<"Client : "<<buffer<<std::endl;// 5. 发送回复 sendtoconstchar*hello="hello from server";::sendto(sockfd,(constchar*)hello,strlen(hello),0,(conststructsockaddr*)&client_addr,len);}close(sockfd);return0;}

客户端

#include<iostream>#include<cstring>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include<unistd.h>#definePORT8080#defineSERVER_IP"127.0.0.1"// 本地回环测试intmain(){// 1. 创建套接字intsockfd=socket(AF_INET,SOCK_DGRAM,0);if(sockfd<0){perror("socket creation failed");return-1;}// 2. 填充目标(服务器)地址信息structsockaddr_inservaddr;memset(&servaddr,0,sizeof(servaddr));servaddr.sin_family=AF_INET;servaddr.sin_port=htons(PORT);// 将字符串IP转换为网络字节序servaddr.sin_addr.s_addr=inet_addr(SERVER_IP);// 3. 直接发送 (Sendto)constchar*hello="Hello from Client";// 注意:UDP是无连接的,必须在发的时候指定发给谁 (&servaddr)sendto(sockfd,(constchar*)hello,strlen(hello),0,(conststructsockaddr*)&servaddr,sizeof(servaddr));std::cout<<"Message sent."<<std::endl;// 4. 接收回复 (Recvfrom)charbuffer[1024];socklen_t len=sizeof(servaddr);// 这里也可以传 NULL,如果你不关心是谁回你的(但在UDP中最好校验源地址)intn=recvfrom(sockfd,(char*)buffer,1024,0,(structsockaddr*)&servaddr,&len);buffer[n]='\0';std::cout<<"Server : "<<buffer<<std::endl;close(sockfd);return0;}
http://www.jsqmd.com/news/373020/

相关文章:

  • 【pySLAM】pySLAM
  • 面向对象高级三
  • LeetCode热题100--42. 接雨水--困难
  • 【无标题】具身智能的长期任务规划与记忆机制
  • 2026年漯河旧房翻新攻略:如何甄选正规靠谱的施工团队? - 2026年企业推荐榜
  • VBA即用型代码手册:设置表格内的字体Set the font in the table
  • 2026年2月漯河高性价比装修实力公司综合评测 - 2026年企业推荐榜
  • 2026年漯河旧房翻新市场深度解析与TOP施工团队权威推荐 - 2026年企业推荐榜
  • 2026年三峡人家旅行社综合服务实力深度评测与选型指南 - 2026年企业推荐榜
  • 对话机器人架构演进:从状态机到神经符号混合系统的组件化实践
  • 宜兴MVR蒸汽压缩机品牌综合实力TOP5盘点(2026版) - 2026年企业推荐榜
  • 2026年无锡蒸汽压缩机可靠制造商深度评析与选型指南 - 2026年企业推荐榜
  • 2026上半年徐州轴连轴承厂家综合实力榜与选型指南 - 2026年企业推荐榜
  • 2026年长沙专业地下室防水补漏师傅哪家强?6家顶尖公司深度解析 - 2026年企业推荐榜
  • 专精特新申报公司评测:2026年2月哪家服务商更可靠? - 2026年企业推荐榜
  • 苹果手机数据传输最全教程:5种好用方法任你选!
  • 可观测性平台厂商排名:国内外核心厂商深度解析
  • 2026年2月宜昌休闲棋牌店铺深度评测:叁友茶社为何领跑口碑榜? - 2026年企业推荐榜
  • 2026年武汉光伏设计服务团队综合选购指南与市场前瞻 - 2026年企业推荐榜
  • Kimi坦诚算力告急引热议 指路DeepSeek
  • 极限脱氮时代,如何挑选技术扎实、效果可视的设备定制伙伴? - 2026年企业推荐榜
  • 追问即元意义:AI元人文的存在论根基与智能时代的意义导航
  • 阿里云Qwen-Image-2.0重磅发布 生成编辑合一碾压盲测
  • 2026年宁波高效除砂设备公司五强榜单及选型指南 - 2026年企业推荐榜
  • 2026湖北烧碱代理选择指南:五大品牌深度评测与推荐 - 2026年企业推荐榜
  • 2026年湖南不锈钢回收服务商综合实力与价格评估 - 2026年企业推荐榜
  • 足部健康新选择:2026年主流鞋垫服务商深度对比与选型指南 - 2026年企业推荐榜
  • 江苏MVR蒸汽压缩机厂商深度评测与选型建议 - 2026年企业推荐榜
  • 前瞻2026:宜兴地区高评价封头制造厂综合解析与选型指南 - 2026年企业推荐榜
  • 2026年武汉光伏电站服务商综合评估与选择指南 - 2026年企业推荐榜