网络编程
一、网络基础核心(底层支撑)
网络协议体系
TCP/IP协议簇(核心)
- 网络层:IP协议(IPv4/IPv6)、ICMP(差错控制)、ARP(地址解析)
- 传输层:TCP(可靠传输)、UDP(轻量传输)
- 应用层:HTTP/HTTPS、FTP、SMTP、DNS、Telnet(面向实际业务)
协议关键细节
- TCP头部:源端口(16位)、目的端口(16位)、序列号(32位)、确认号(32位)、标志位(SYN/FIN/ACK/RST/PSH)
- UDP头部:源端口(16位)、目的端口(16位)、总长度(16位)、校验和(16位)
- IP头部:版本(4位)、TTL(生存时间)、协议字段(标识上层协议:TCP=6/UDP=17)
网络分层模型
- OSI七层模型(理论参考):物理层(硬件)→ 数据链路层(帧传输)→ 网络层(路由)→ 传输层(端到端)→ 会话层(连接管理)→ 表示层(数据编码)→ 应用层(业务逻辑)
- TCP/IP四层模型(实际应用):网络接口层(对应OSI前两层)→ 网络层 → 传输层 → 应用层(整合OSI后三层)
- 分层核心意义:解耦,每层仅关注自身功能,通过接口交互
地址与端口体系
IP地址
- IPv4:32位(点分十进制,如192.168.1.1),分类A/B/C/D/E,私有IP段(10.0.0.0/8、172.16.0.0/12、192.168.0.0/16)
- IPv6:128位(冒分十六进制,如2001:0db8:85a3:0000:0000:8a2e:0370:7334),解决IPv4地址枯竭
- 特殊IP:127.0.0.1(本机回环)、0.0.0.0(监听所有本机IP)、255.255.255.255(广播地址)
端口与端口映射
-
端口范围:0-65535(16位无符号整数),0-1023为系统保留端口(如HTTP=80、HTTPS=443、FTP=21)
-
核心作用:标识同一主机上的不同应用进程,实现"IP+端口"唯一寻址
-
子网与网关:子网掩码(划分网络位与主机位)、网关(跨子网通信的出入口)
二、Socket编程基础(编程入口)
Socket核心概念
定义:
应用层与传输层的抽象接口,本质是内核中的文件描述符,关联"IP+端口",是通信的唯一标识
套接字类型
- 流式套接字(SOCK_STREAM):面向连接、可靠有序、字节流,TCP专用
- 数据报套接字(SOCK_DGRAM):无连接、不可靠、数据报,UDP专用
- 原始套接字(SOCK_RAW):直接操作底层协议(如IP/TCP),用于抓包、自定义协议(需管理员权限)
字节序与格式转换
- 字节序:网络字节序(大端序,高位在前)、主机字节序(x86为小端序,低位在前)
- 转换函数:htonl(主机→网络,32位整数)、htons(主机→网络,16位整数)、ntohl/ntohs(网络→主机)
- IP格式转换:inet_addr(字符串IPv4→网络字节序)、inet_ntoa(网络字节序→字符串IPv4)、inet_pton/inet_ntop(支持IPv4/IPv6)
核心数据结构
- sockaddr_in(IPv4专用):sin_family(AF_INET)、sin_port(端口,网络字节序)、sin_addr(IP地址,struct in_addr)
- sockaddr(通用地址结构):兼容IPv4/IPv6,需强制类型转换
- in_addr:存储IPv4地址(32位整数)
关键工具函数
- 套接字控制:socket(创建套接字)、bind(绑定IP+端口)、listen(设置监听队列)、accept(接收连接)、connect(发起连接)
- 数据读写:read/write(字节流读写,TCP)、send/recv(带选项的TCP读写)、sendto/recvfrom(UDP数据报收发,需指定目标地址)
- 选项配置:setsockopt(设置套接字选项,如SO_REUSEADDR端口复用、SO_BROADCAST允许广播、SO_RCVTIMEO设置接收超时)、getsockopt(获取选项配置)
- 错误处理:perror(打印系统错误信息)、strerror(获取错误描述字符串)
三、TCP编程详解(可靠传输场景)
连接核心机制
三次握手(建立连接)
- 过程:客户端发送SYN(序列号=x)→ 服务器回复SYN+ACK(序列号=y,确认号=x+1)→ 客户端回复ACK(确认号=y+1)
- 目的:同步序列号,确保双方收发能力正常,避免历史无效连接
- 状态变化:客户端(CLOSED→SYN_SENT→ESTABLISHED)、服务器(CLOSED→LISTEN→SYN_RCVD→ESTABLISHED)
四次挥手(关闭连接)
- 过程:客户端发送FIN(请求关闭)→ 服务器回复ACK → 服务器发送FIN → 客户端回复ACK
- 目的:双向关闭连接,确保双方数据均已传输完成
- 状态变化:FIN_WAIT_1、CLOSE_WAIT、FIN_WAIT_2、LAST_ACK、TIME_WAIT(客户端最终等待2MSL,避免端口占用)
完整编程流程
服务器端(被动连接)
- socket:创建TCP套接字(AF_INET + SOCK_STREAM)
- setsockopt:设置SO_REUSEADDR,避免端口释放后处于TIME_WAIT状态无法复用
- bind:将套接字绑定到指定IP和端口(sin_family=AF_INET,sin_addr=INADDR_ANY,sin_port=htons(端口))
- listen:设置监听队列长度(如listen(fd, 5),5为半连接队列大小)
- accept:阻塞等待客户端连接,返回新的通信套接字(与客户端一一对应)
- read/write:通过新套接字与客户端传输数据
- close:关闭通信套接字和监听套接字
客户端(主动连接)
- socket:创建TCP套接字
- connect:指定服务器IP和端口,发起连接(需服务器处于LISTEN状态)
- read/write:与服务器传输数据
- close:关闭套接字
并发服务器模型(解决单连接阻塞问题)
- 多进程并发:accept后fork子进程,子进程处理客户端请求,父进程继续监听(优点:隔离性好;缺点:进程切换开销大)
- 多线程并发:accept后创建线程,线程处理请求(优点:开销小;缺点:需处理线程安全,如共享资源加锁)
- IO复用并发:select/poll/epoll(单进程/线程管理多个套接字),适用于高并发场景(如百万连接)
- select:监听文件描述符集合,支持跨平台,最大限制1024
- poll:无文件描述符数量限制,基于链表存储
- epoll:Linux专用,高效(事件驱动,仅通知变化的套接字),支持水平触发(LT)和边缘触发(ET)
关键问题与解决方案
- TCP粘包:数据无边界导致连续发送的数据包被合并接收
- 解决方案:定长数据包、分隔符(如\n)、包头+包体(包头存储数据长度)
- 超时处理:connect/send/recv阻塞导致程序卡死
- 解决方案:setsockopt设置SO_RCVTIMEO/SO_SNDTIMEO、select设置超时时间
- 断连重连:网络异常导致连接中断
- 解决方案:心跳包(定期发送小数据包检测连接)、捕获RST信号触发重连
四、UDP编程详解(实时传输场景)
协议核心特性
- 无连接:无需三次握手,直接发送数据,减少延迟
- 不可靠:无确认、无重传、无排序,数据可能丢包、乱序、重复
- 轻量高效:头部仅8字节,开销远低于TCP,适合短报文传输
- 支持多通信模式:一对一、一对多(广播)、多对多(组播)
完整编程流程
服务器端
- socket:创建UDP套接字(AF_INET + SOCK_DGRAM)
- bind:绑定IP和端口(必须绑定,否则无法接收客户端数据)
- recvfrom:阻塞接收数据,同时获取客户端IP和端口(struct sockaddr_in cli_addr)
- sendto:根据客户端地址回复数据
- close:关闭套接字
客户端
- socket:创建UDP套接字
- sendto:指定服务器IP和端口,发送数据(无需connect)
- recvfrom:接收服务器响应(可设置超时)
- close:关闭套接字
特殊通信模式
UDP广播
- 特点:仅在本地子网内传播(路由器不转发广播包),实现"点对多"
- 配置流程:setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) → 绑定端口 → 向255.255.255.255发送数据
- 接收方:绑定相同端口,通过recvfrom接收广播包
UDP组播(多播)
- 特点:跨子网通信,仅组内成员接收,带宽占用低(优于广播)
- 核心协议:IGMP(互联网组管理协议,用于加入/退出组播组)
- 配置流程:创建UDP套接字 → setsockopt设置IP_ADD_MEMBERSHIP(加入组播组,指定组播IP和本地网卡IP) → 绑定端口 → 收发数据
- 组播IP:D类地址(224.0.0.0-239.255.255.255),其中224.0.0.0-224.0.0.255为保留地址
可靠性增强(应用层补充)
- 需求场景:需UDP低延迟,又需一定可靠性(如游戏、视频通话)
- 实现方案:应用层添加序列号(排序去重)、确认应答(ACK)、超时重传、窗口流量控制
五、应用层协议编程(实际业务落地)
常用应用层协议实操
HTTP/HTTPS编程
- HTTP特点:无状态、基于TCP,请求-响应模式
- 核心操作:构造HTTP请求(GET/POST方法,请求头Host/User-Agent/Content-Type)、解析HTTP响应(状态码200/404/500,响应体数据)
- HTTPS:HTTP+SSL/TLS加密,需使用OpenSSL库实现证书验证、加密传输
DNS编程
- 功能:将域名(如www.baidu.com)解析为IP地址
- 实现方式:调用系统函数(gethostbyname、getaddrinfo)、基于UDP实现DNS查询协议(向DNS服务器53端口发送查询报文)
FTP编程
- 模式:主动模式(服务器主动连接客户端)、被动模式(客户端主动连接服务器)
- 核心操作:登录(USER/PASS)、上传(STOR)、下载(RETR)、列出目录(LIST)
自定义应用层协议设计
- 设计原则:简洁、易解析、可扩展
- 协议格式:包头(固定长度,含版本号、数据长度、校验和、命令类型)+ 包体(业务数据,如JSON/protobuf编码)
- 数据编码:JSON(可读性强,适合小数据)、protobuf(二进制编码,高效紧凑,适合大数据/跨平台)
六、网络编程工具与调试(开发助力)
1. 抓包分析工具
Wireshark为可视化抓包工具,支持过滤TCP、UDP、HTTP等各类协议,可直观查看数据包头部信息、数据内容,便于定位协议交互问题;tcpdump为Linux命令行抓包工具,功能强大,如"tcpdump -i eth0 port 80"命令可抓取eth0网卡80端口的所有数据,适合服务器端无图形界面场景。
2. 端口与连接查看
netstat命令用于查看端口状态和网络连接,如"netstat -anp | grep 8080"可查看8080端口的占用情况及对应进程;ss命令为Linux下替代netstat的工具,效率更高,如"ss -tuln"可快速查看当前监听的TCP和UDP端口。
3. 连接测试工具
telnet工具用于测试TCP端口连通性,如"telnet 127.0.0.1 8080"可测试本地8080端口是否能正常连接;nc(netcat)为多功能网络工具,支持TCP/UDP连接建立、端口扫描、数据传输,可模拟客户端和服务器端,辅助调试网络程序。
4. 日志与调试技巧
开发过程中需打印关键信息日志,包括通信双方IP、端口、数据包长度、错误码等,便于问题回溯;模拟网络异常场景时,可使用iptables(Linux防火墙)限制端口访问,或通过tc命令模拟网络丢包、延迟,验证程序容错能力。
七、关键优化与注意事项(生产级要求)
1. 性能优化
TCP优化:调整系统参数net.core.somaxconn增大监听队列长度,开启TCP_NODELAY选项禁用Nagle算法(减少延迟),启用SO_KEEPALIVE选项保持长连接,避免频繁建立连接开销。UDP优化:通过setsockopt设置SO_RCVBUF增大接收缓冲区,避免数据溢出;控制数据包大小,避免超过MTU(默认1500字节)导致分片,影响传输效率。IO优化:采用非阻塞IO结合epoll(Linux)/IOCP(Windows)机制,减少系统调用次数,批量处理读写操作,提升并发能力。
2. 兼容性与安全性
跨平台兼容:Windows和Linux的Socket API存在差异,如Windows需调用WSAStartup初始化网络环境,关闭套接字使用closesocket函数,开发时需做好条件编译,保证跨平台运行。安全防护:校验接收数据包的合法性(如长度、格式、来源),防止恶意攻击;避免缓冲区溢出(固定接收长度,对输入数据做限制);敏感数据(如用户名、密码)需加密传输(采用HTTPS或自定义加密算法)。
3. 常见坑点规避
忘记设置SO_REUSEADDR选项,导致端口释放后处于TIME_WAIT状态,短期内无法重启程序;UDP服务器未绑定端口,导致无法接收客户端数据;未处理TCP粘包问题,导致数据解析错误;忽略字节序转换,直接使用主机字节序绑定端口或设置IP,导致跨平台通信失败;未设置超时机制,导致程序因网络异常长期阻塞。