学习笔记——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);
}
相关推荐
semantist@语校2 小时前
第五十七篇|东京银星日本语学校的数据建模:高密度城市中的学习节律、制度边界与 Prompt 接口设计
大数据·数据库·人工智能·学习·百度·prompt·知识图谱
深蓝海拓2 小时前
PySide6从0开始学习的笔记(十二) QProgressBar(进度条)
笔记·python·qt·学习·pyqt
ICT技术最前线2 小时前
华为交换机VLAN配置命令详解
服务器·网络·vlan·华为交换机
zhendianluli2 小时前
为什么fclose处理的是file而不是fd
linux·服务器·网络
牙牙7052 小时前
部署SFTP服务
linux·服务器·网络
人工智能训练2 小时前
Ubuntu 系统安装 VSCode 超全指南(3 种方法,适配 20.04/22.04 LTS)
linux·运维·服务器·vscode·ubuntu
绾樘2 小时前
HCIP—OSPF综合实验
网络·智能路由器
TG:@yunlaoda360 云老大2 小时前
华为云国际站代理商的CloudPond跨境主要有什么用呢?
服务器·网络·华为云
bing_feilong2 小时前
ubuntu网络命令详解
linux·运维·网络