一、定义与值
- 头文件:定义在<netinet/in.h>(Linux/Unix)或 <winsock2.h>(Windows)中:
#define IPPROTO_TCP 6 /* TCP 协议 */
- 值:6,对应IANA分配的TCP协议号
- 层级:属于传输层协议(OSI第四层),基于IP协议(网络层)工作
二、核心作用
1. 标识TCP协议
- 在套接字(Socket)编程中,指定使用TCP协议进行数据传输
- 在IP数据包头部中,Protocol字段值为6时,表示负载是TCP数据段
2. 启用TCP特性
特性 | 说明 |
可靠传输 | 通过确认重传(ACK)、序列号、校验和确保数据不丢失、不重复、有序。 |
流量控制 | 滑动窗口机制防止发送方压垮接收方。 |
拥塞控制 | 动态调整发送速率(如慢启动、拥塞避免),避免网络拥堵。 |
面向连接 | 通信前需通过三次握手建立连接,通信后通过四次挥手释放连接。 |
三、实际应用场景
1. 创建TCP套接字
#include <sys/socket.h>
// 创建 TCP 套接字
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- SOCK_STREAM:表示使用流式传输(TCP的典型特征)
- IPPROTO_TCP:显示指定TCP协议(通常可省略,因为SOCK_STREAM已隐含TCP)
2. 设置TCP套接字选项
int enable_keepalive = 1;
setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &enable_keepalive, sizeof(enable_keepalive));
- TCP_KEEPALIVE :启用保活机制检测连接存活
- TCP_NODELAY:禁用Nagle算法(减少小数据包的延迟)
3. 抓包分析TCP流量

四、TCP数据段格式
TCP数据段的头部结构如下:
源端口(Source Port) | 2 | 发送方端口号。 |
目标端口(Dest Port) | 2 | 接收方端口号。 |
序列号(Sequence Number) | 4 | 数据段的顺序标识。 |
确认号(Ack Number) | 4 | 期望接收的下一个序列号(ACK 机制)。 |
数据偏移(Data Offset) | 0.5 | TCP 头部的长度(以 4 字节为单位)。 |
标志位(Flags) | 0.5~1 | SYN、ACK、FIN、RST 等控制位。 |
窗口大小(Window Size) | 2 | 接收方的可用缓冲区大小(流量控制)。 |
校验和(Checksum) | 2 | 数据完整性校验。 |
紧急指针(Urgent Pointer) | 2 | 紧急数据的偏移量(若 URG 标志置1)。 |
五、常见协议号对比
常量 | 值 | 协议 | 特性 |
IPPROTO_TCP | 6 | TCP | 可靠、面向连接、流量控制。 |
IPPROTO_UDP | 17 | UDP | 无连接、不可靠、低延迟。 |
IPPROTO_ICMP | 1 | ICMP | 网络层错误与控制消息(如 ping)。 |
IPPROTO_ICMPV6 | 58 | ICMPv6 | IPv6 的 ICMP 协议。 |
六、代码示例
1. 创建TCP服务器(C)
#include <sys/socket.h>
#include <netinet/in.h>
int main() {
// 创建 TCP 套接字
int server_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8080);
addr.sin_addr.s_addr = INADDR_ANY;
// 绑定并监听
bind(server_fd, (struct sockaddr *)&addr, sizeof(addr));
listen(server_fd, 5);
// 接受连接
int client_fd = accept(server_fd, NULL, NULL);
// ... 数据读写操作 ...
return 0;
}
2. 发送TCP数据(Python)
import socket
# 创建 TCP 套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("example.com", 80))
# 发送 HTTP 请求
sock.send(b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n")
response = sock.recv(4096)
print(response.decode())
sock.close()
七、注意事项
1. 协议号冲突:
- 在原始套接字(Raw Socket)中构造IP数据包时,需将IP头部的Protocol字段设为6,否则接收方无法正确解析TCP数据。
2. NAT与防火墙:
- TCP的端口和连接状态会被NAT设备跟踪,需注意长连接保活
- 防火墙通常根据IPPROTO_TCP和端口号过滤流量(如允许80端口的HTTP)
3. 性能调优:
- 调整TCP缓冲区大小
int buffer_size = 1024 * 1024;
setsockopt(sock, IPPROTO_TCP, SO_RCVBUF, &buffer_size, sizeof(buffer_size));
setsockopt(sock, IPPROTO_TCP, SO_SNDBUF, &buffer_size, sizeof(buffer_size));
- 禁用Nagle算法(需权衡延迟与吞吐量)
int flag = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
八、总结
- 本质:标识TCP协议的常量(协议号=6)
- 用途:
- 在传输层启用TCP的可靠传输机制
- 在套接字编程中显式指定TCP协议
- 关键特性:面向连接、可靠传输、流量与拥塞控制
- 适用场景:需要高可靠性的应用(如web、文件传输、数据库访问)