学习笔记——TCP 传输控制协议

TCP 传输控制协议笔记整理

一、网络模型

1. CS模型 (Client-Server)

  • 客户端(Client):专用客户端程序

  • 服务器(Server):提供服务

  • 特点

    • 专用客户端

    • 使用自定义协议

    • 功能相对复杂

    • 资源在本地

2. BS模型 (Browser-Server)

  • 浏览器(Browser):通用客户端

  • 服务器(Server):提供服务

  • 特点

    • 通用客户端(浏览器)

    • 使用HTTP协议

    • 功能相对简单

    • 资源由服务器发送

3. P2P模型 (Peer-to-Peer)

  • 特点

    • 既是客户端也是服务器

    • 同时下载和上传

    • 网络下载工具常用

    • 新客户端可以从其他客户端下载数据

二、TCP协议特点

1. 基本特征

  • 有连接:需要三次握手建立连接

  • 可靠传输:通过确认机制保证数据完整

  • 流式套接字:数据没有边界,连续有序

  • 全双工:双缓冲区,可同时收发

  • 感知断开:能感知对方断开(四次挥手)

2. 可靠性保证

复制代码
1. 应答机制 (ACK)     - 确认收到数据
2. 超时重传           - 未收到确认则重发
3. 实时性弱           - 为保证可靠牺牲实时性
4. 网络资源消耗大     - 需要更多资源维护连接

3. 黏包问题

  • 现象:TCP数据无边界,接收方可能一次性接收多个数据包

  • 原因:发送方多次发送,接收方一次性接收

  • 解决方案:需要应用层协议定义数据边界

三、TCP函数详解

1. socket() - 创建套接字

复制代码
int socket(int domain, int type, int protocol);

参数

  • domain:地址族

    • PF_INET / AF_INET:互联网程序

    • PF_UNIX / AF_UNIX:单机程序

  • type:套接字类型

    • SOCK_STREAM:流式套接字(TCP)

    • SOCK_DGRAM:数据报套接字(UDP)

    • SOCK_RAW:原始套接字(IP)

  • protocol:协议,0表示自适应

2. bind() - 绑定地址

复制代码
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);

功能:将套接字与地址绑定(服务器端)

3. listen() - 监听连接

复制代码
int listen(int sockfd, int backlog);

参数

  • backlog:允许三次握手的排队数

4. accept() - 接受连接

复制代码
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

参数说明

  • addr:客户端地址

    • NULL:不关心客户端信息

    • NULL:存储客户端信息

  • addrlen:地址长度

    • addrNULL时,该值也为NULL

    • NULL时:len = sizeof(struct sockaddr)

5. recv() - 接收数据

复制代码
ssize_t recv(int sockfd, void *buf, size_t len, int flags);

参数说明

  • sockfd

    • 服务器:accept()返回值

    • 客户端:socket()返回值

  • flags:接收方式,0表示阻塞接收

  • 返回值:实际接收的数据长度

6. send() - 发送数据

复制代码
int send(int sockfd, const void *msg, size_t len, int flags);

参数说明

  • sockfd

    • 服务器:accept()返回值

    • 客户端:socket()返回值

7. connect() - 连接服务器

复制代码
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

功能:客户端连接服务器

四、TCP编程流程

服务器端流程:

复制代码
socket() -> bind() -> listen() -> accept() -> recv()/send() -> close()

客户端流程:

复制代码
socket() -> connect() -> send()/recv() -> close()

五、重要概念

1. 监听套接字 vs 通信套接字

  • 监听套接字:用于接受连接请求

  • 通信套接字:用于实际数据传输

  • 关系:一个监听套接字可生成多个通信套接字

2. 连接建立与断开

复制代码
三次握手建立连接:
  客户端 -> SYN -> 服务器
  客户端 <- SYN+ACK <- 服务器
  客户端 -> ACK -> 服务器

四次挥手断开连接:
  主动方 -> FIN -> 被动方
  被动方 <- ACK <- 被动方
  被动方 -> FIN -> 主动方
  主动方 <- ACK <- 主动方

六、函数调用顺序表

步骤 服务器端 客户端
1 socket() socket()
2 bind()
3 listen()
4 accept() connect()
5 recv()/send() send()/recv()
6 close() close()

七、注意事项

  1. 写阻塞:缓冲区满时会发生写阻塞(约64K)

  2. 收发次数:发送次数和接收次数不需要对应

  3. 地址处理 :使用inet_ntoa()htons()进行地址转换

  4. 错误处理:所有网络函数都应检查返回值

  5. 资源释放:使用完毕后关闭套接字和文件描述符

八、示例代码框架

服务器框架:

复制代码
int main() {
    // 1. 创建socket
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    
    // 2. 绑定地址
    struct sockaddr_in addr;
    bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
    
    // 3. 监听
    listen(sockfd, 5);
    
    // 4. 接受连接
    int connfd = accept(sockfd, NULL, NULL);
    
    // 5. 通信
    char buf[1024];
    recv(connfd, buf, sizeof(buf), 0);
    send(connfd, buf, strlen(buf), 0);
    
    // 6. 关闭
    close(connfd);
    close(sockfd);
}

客户端框架:

复制代码
int main() {
    // 1. 创建socket
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    
    // 2. 连接服务器
    struct sockaddr_in server_addr;
    connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    
    // 3. 通信
    send(sockfd, "hello", 5, 0);
    recv(sockfd, buf, sizeof(buf), 0);
    
    // 4. 关闭
    close(sockfd);
}
相关推荐
HelloWorld工程师20 分钟前
新手如何快速申请SSL通配符证书...
网络协议·https·ssl
Funing71 小时前
FreeRTOS学习day1:Keil 工程配置与 FreeRTOS 链表机制理解
数据结构·学习·链表
醉熏的石头1 小时前
Ubuntu 中的编程语言(中)
linux·ubuntu·scala
心中有国也有家1 小时前
使用 DevEco Studio 配置 Flutter 鸿蒙签名
学习·flutter·华为·harmonyos
灯澜忆梦1 小时前
MySQL 完整学习路线
学习·mysql
番茄育学园1 小时前
我的三款主流云存储音乐库实测笔记
笔记·分类·媒体
森林古猿12 小时前
再论斜率优化
c++·学习·算法
心中有国也有家3 小时前
鸿蒙Flutter开发环境从零搭建教程(Windows/macOS双平台·避坑版)
学习·flutter·华为·harmonyos
十月的皮皮4 小时前
C语言学习笔记20260706-栈的压入、弹出序列验证
c语言·笔记·学习
dddwjzx4 小时前
嵌入式Linux C应用编程入门——信号
linux·嵌入式