Linux网络部分——UDP内部链接关系,服务端、客户端在网络中的联系,公网、内网、本地环回

发布时间:2026/8/9 14:17:08
Linux网络部分——UDP内部链接关系,服务端、客户端在网络中的联系,公网、内网、本地环回 bit::Shadow✧(≖ ◡ ≖✿目录认识UDP、TCP协议一、UDP 是什么一句话定义二、UDP 的核心特点对比 TCP网络字节序☆☆判断网络转主机还是主机转网络的关键是什么struct sockaddr_in local成员变量详解struct sockaddr的继承体系公网、内网、本地环回四大接口简解基于Udp的实现套接字socket()创建的含义进行bind()的含义recvfrom的含义sendto()的含义在服务器客户端分别实现时IP与端口号的指定情况是什么1. 服务器端被动等待连接/数据2. 客户端主动发起请求3. 特殊情况同一台机器上测试4. 一张图总结对比在同一台电脑上运行服务器和客户端常见于开发调试服务器绑定 0.0.0.0 都行客户端的目标IP直接写 内网IP本地回环公网IP都可以吗原因是什么服务器绑定 0.0.0.0 意味着什么两台电脑一台客户端、一台服务器端使用公网链接可以吗1. 为什么“可以”技术层面2. 为什么“几乎不可能”现实网络层面——这是关键服务器端被连接方的致命问题设计原则类设计Init()中socket()是必要构造函数内_port是服务器需求使然。认识UDP、TCP协议一、UDP 是什么一句话定义UDPUser Datagram Protocol用户数据报协议是传输层的一种无连接、不可靠、面向数据报的协议。它只在 IP 之上增加了端口号用于区分进程和简单的校验和不保证数据一定到达、不保证顺序、不保证不重复。二、UDP 的核心特点对比 TCP特性UDPTCP连接状态无连接发送前不需要握手面向连接三次握手可靠性不可靠不保证送达可靠超时重传、确认机制顺序性不保证顺序保证按序到达拥塞控制无发送速率不受网络限制有滑动窗口、慢启动流量控制无有数据边界面向数据报一次发送一个完整报文面向字节流无边界校验和有可选但通常开启有必须开销头部 8 字节头部 20-60 字节传输速度快慢相对网络字节序即信息在网络中必须以大端形式传输。网络、主机转换四大接口常用于网络中端口的转接#includearpa/inet.h //主机转网络 uint16_t htons(uint16_t hostShort); uint32_t htonl(uint32_t hostLong); //网络转主机 uint16_t ntohs(uint16_t netShort); uint32_t ntohl(uint32_t netLong);☆☆判断网络转主机还是主机转网络的关键是什么凡是你要“塞给”内核或网络的用hton主机转网络还是内核或网络“塞给你”的用ntoh网络转主机。struct sockaddr_in local使用struct sockaddr_in必须包含额外的头文件#includenetinet/in.hstruct sockaddr_in local;这行代码是网络编程中最核心的地址结构体定义。它定义了一个名为local的变量专门用来存储IPv4 套接字地址即 IP 地址 端口号。// 在 netinet/in.h 中定义 struct sockaddr_in { sa_family_t sin_family; // 地址族必须设置为 AF_INET in_port_t sin_port; // 端口号网络字节序 struct in_addr sin_addr; // IPv4 地址网络字节序 unsigned char sin_zero[8]; // 填充字段确保与 struct sockaddr 大小一致 }; // 其中 struct in_addr 的定义 struct in_addr { uint32_t s_addr; // IPv4 地址32位网络字节序 };成员变量详解字段类型含义必须设置的值示例sin_familysa_family_t通常是unsigned short地址族标识这是 IPv4 地址AF_INETlocal.sin_family AF_INET;sin_portin_port_t通常是uint16_t端口号16位必须用htons()转为网络字节序你想要的端口号如 8888local.sin_port htons(8888);sin_addrstruct in_addrIP 地址32位若指定必须用htonl()或inet_pton()转为网络字节序你的 IP 或INADDR_ANYlocal.sin_addr.s_addr INADDR_ANY;sin_zerounsigned char[8]填充字段只为保证结构体大小一致16字节通常用memset清零0memset(local.sin_zero, 0, sizeof(local.sin_zero));bzero(local,sizeof(local));struct sockaddr的继承体系公网、内网、本地环回公网IP内网、本地环回四大接口简解基于Udp的实现套接字socket()创建的含义向内核申请一个“网络通信端点”返回一个文件描述符fd后续所有网络操作都通过它来标识这个通信通道。进行bind()的含义把套接字与一个本地 IP 地址和端口号关联起来告诉内核“这个套接字负责接收发往这个 IP:端口 的数据”。recvfrom的含义从套接字的接收缓冲区中取出一个 UDP 数据报同时把发送方的 IP 地址和端口号返回给调用者。sendto()的含义把数据封装成 UDP 数据报发送到指定的目标 IP 地址和端口。在服务器客户端分别实现时IP与端口号的指定情况是什么这是一个非常核心的网络编程概念问题。我直接给你最清晰、最实操的答案。核心结论服务器Server必须明确指定自己的IP和端口尤其是端口。客户端Client必须指定服务器的IP和端口但通常不需要指定自己的IP和端口由操作系统自动分配。同一台机器服务端IPIADDR_ANY客户端IP指定自己的本地IP。ifconfig不同台机器服务端IPINADDR_ANY客户端IP指定服务端机器本身的IP规定端口。1. 服务器端被动等待连接/数据服务器是“被找到”的一方所以必须有一个固定的“门牌号”。IP地址必须明确。如果你想只允许本机访问测试用绑定127.0.0.1。如果你想让同一局域网WiFi/有线内的其他机器访问绑定你查到的内网IP如192.168.1.100。如果你想让本机所有网卡包括127.0.0.1和192.168.1.100都能访问绑定0.0.0.0INADDR_ANY。这是服务器最常用的写法代码通用性最强。端口号必须明确指定如8080、8888。这是操作系统区分不同服务的唯一标识。代码体现UDP Server绑定当不指定时自然可以接受任何IP的链接// 服务器的固定据点 server_addr.sin_family AF_INET; server_addr.sin_addr.s_addr INADDR_ANY; // 或者 inet_addr(192.168.1.100) server_addr.sin_port htons(8888); // 固定端口此处明确 bind(server_fd, (struct sockaddr*)server_addr, sizeof(server_addr));2. 客户端主动发起请求客户端是“主动寻找”的一方。它只需要知道“我要找谁”而不需要关心“我是谁”。必须指定目标服务器的IP和服务器的端口号。这是你连接的目标。无需指定自身客户端自己的IP和端口号完全可以不写。当你在客户端调用sendto()或connect()之前如果没有手动bind()操作系统内核会自动帮你随机挑选一个空闲端口比如52341作为源端口并自动选择合适的网卡IP作为源IP。只有一种情况需要客户端手动绑定如果你的程序运行在防火墙严格限制的机器上必须使用固定端口通信。代码体现UDP Client发送数据// 明确指定要“找谁”服务器 server_addr.sin_family AF_INET; server_addr.sin_addr.s_addr inet_addr(192.168.1.100); // 服务器的IP server_addr.sin_port htons(8888); // 服务器的端口 // 自己的IP和端口不需要直接发系统会自动分配 sendto(sock_fd, buffer, len, 0, (struct sockaddr*)server_addr, sizeof(server_addr));3. 特殊情况同一台机器上测试如果你是在同一台电脑上运行服务器和客户端常见于开发调试服务器绑定127.0.0.1或0.0.0.0都行客户端的目标IP直接写127.0.0.1。4. 一张图总结对比角色本机IP自己本机端口自己目标IP对方目标端口对方服务器 (Server)必须指定固定常用INADDR_ANY必须指定固定如8888无需关心无需关心客户端 (Client)无需指定系统自动分配无需指定系统自动分配随机端口必须指定服务器的IP必须指定服务器的端口在同一台电脑上运行服务器和客户端常见于开发调试服务器绑定 0.0.0.0 都行客户端的目标IP直接写 内网IP本地回环公网IP都可以吗原因是什么直接给你结论是的都可以在同一台电脑上只要服务器绑定了0.0.0.0客户端的目标IP无论是写内网IP如192.168.1.100、本地回环127.0.0.1还是公网IP如你的运营商分配的外网IP都能成功通信。但这背后有一个非常硬核的操作系统网络栈原理。我把这3种情况拆开给你讲透你就彻底明白了。服务器绑定0.0.0.0意味着什么0.0.0.0INADDR_ANY在操作系统中是一个“通配符”。它不是一个真正的网卡IP。它的意思是“只要是发往这台电脑上任意一个IP地址且端口号匹配的数据包我都收”这意味着你的服务器进程同时“注册”在了这台电脑的所有IP上127.0.0.1回环网卡192.168.1.100有线/无线网卡xxx.xxx.xxx.xxx公网IP如果有的话所以无论客户端从哪个IP发过来服务器都能收到。两台电脑一台客户端、一台服务器端使用公网链接可以吗1. 为什么“可以”技术层面只要两台电脑都能访问互联网并且互相知道对方的公网IP代码逻辑上完全没问题。你的UDP Socket代码不需要改一行服务器绑定0.0.0.0接收所有IP的数据。客户端sendto的目标IP填服务器的公网IP比如120.xxx.xxx.xxx。从编程角度看IP地址只是一个32位的数字填什么它就发往哪里代码绝对支持。2. 为什么“几乎不可能”现实网络层面——这是关键现在的家庭宽带、公司网络、手机热点几乎全都使用了NAT网络地址转换。简单来说你的电脑根本没有独立的公网IP。路由器把唯一的公网IP分给了成百上千台设备手机、电脑、电视。服务器端被连接方的致命问题你的服务器运行在笔记本上笔记本拿到的IP是192.168.1.100内网IP。路由器把公网IP120.xxx.xxx.xxx映射给了整个家庭网络。当客户端向120.xxx.xxx.xxx:8888发数据时数据到达路由器路由器懵了“这个8888端口是给哪台电脑的我没设置过啊” 然后直接丢弃数据包。结论默认情况下外网主动发起的连接无法穿透你的家庭路由器到达你的笔记本。这就是所谓的“无公网IP”或“端口不通”。感谢支持长期连载欢迎关注