TCP传输控制协议
cs ,client ,server
bs ,browser(浏览器),server
p2p peer to peer
cs ,bs 区别
cs, 专用客户段
bs ,通用的客户端
2.使用协议
Cs ,应用,标准,自定义
bs 应用层 http
3.功能强弱
cs 相对复杂
bs 相对简单
4. 资源
Cs ,资源在本地
Bs ,由发送给客户
在p2p 网络下载工具中,用的多。
刚开始下载数据的时候,自己的进度是0%, 会有其他的客户端,和服务器,给 咱们自己传递数据。
随着时间的推移,自己的下载进度到了90%,这个时候会有其他的新到达客户端,开始下载数据。
咱们自己也会给新到达的客户端,发送数据。在整个过程中,自己及时下载者,也是上传者。所有身份, 相当于及时客户端,也是服务器
特征:
1.有链接 三次握手
- 可靠传输
3.流式套接字,数据没有边界。 连续的,有顺序的。
4.全双工,双缓存区
5.发送次数和接收次数不需要对应。
6.有写阻塞 64K
7 如果对方端口连接,另外一方可以感知 4次挥手

1.应答 ack num
2.超时重传
- 实时性弱
4.网络资源消耗大
有链接,服务器和客户端之间,一旦连接建立。链路就会一直保持。 直到其中一方表示要断
在利用Wireshark工具进行抓包的时候只有三次挥手,因为系统将【ACK】和【自己的 FIN】合并了再发出去,所以看起来少了一个

使用wireshark抓包的时候,如果外网ens33,如果是测试自己与自己连接用回环接口loopback,不确定时使用any即可
监听套接字和通信套接字的关系

tcp 相关函数
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 表示自动适应应用层协议。
返回值:成功 返回申请的套接字id
失败 -1;

绑定地址可以不用写固定ip地址,可以调用宏INADDR_ANY
该宏代表监听本机所有网卡(回环 lo、内网网卡、公网网卡),任何网卡收到目标端口 50000 的包,这个 socket 都能接收
2、int bind(int sockfd, struct sockaddr *my_addr,socklen_t addrlen);
功能:如果该函数在服务器端调用,则表示将参数1相关
的文件描述符文件与参数2 指定的接口地址关联,
用于从该接口接受数据。
3、 int listen(int sockfd, int backlog);
功能:在参数1所在的套接字id上监听等待链接。
参数:sockfd 套接字id
backlog 允许三次握手的排队数。
返回值:成功 0
失败 -1;

3、 int listen(int sockfd, int backlog);
功能:在参数1所在的套接字id上监听等待链接。
参数:sockfd 套接字id
backlog 允许三次握手的排队数。
返回值:成功 0
失败 -1;

4、int accept(int sockfd, struct sockaddr *addr,socklen_t *addrlen);
功能:从已经监听到的队列中取出有效的客户端链接并
接入到当前程序。
参数:sockfd 套接字id
addr 如果该值为NULL ,表示不论客户端是谁都接入。
如果要获取客户端信息,则事先定义变量
并传入变量地址,函数执行完毕将会将客户端
信息存储到该变量中。
addrlen: 参数2的长度,如果参数2为NULL,则该值
也为NULL;
如果参数不是NULL,&len;
一定要写成len = sizeof(struct sockaddr);
返回值:成功 返回一个用于通信的新套接字id; 通信套接字
从该代码之后所有通信都基于该id
失败 -1;

5.ssize_t recv(int sockfd, void *buf, size_t len,
int flags);
功能:从指定的sockfd套接字中以flags方式获取长度
为len字节的数据到指定的buff内存中。
参数:sockfd
如果服务器则是accept的返回值的新fd
如果客户端则是socket的返回值旧fd
buff 用来存储数据的本地内存,一般是数组或者
动态内存。
len 要获取的数据长度
flags 获取数据的方式,0 表示阻塞接受。
返回值:成功 表示接受的数据长度,一般小于等于len
失败 -1;

- int send(int sockfd, const void *msg,size_t len, int flags);
功能:从msg所在的内存中获取长度为len的数据以flags
方式写入到sockfd对应的套接字中。
参数:sockfd:
如果是服务器则是accept的返回值新fd
数据封包拆包
协议头
如果是客户端则是sockfd的返回值旧fd
msg 要发送的消息
len 要发送的消息长度
flags 消息的发送方式。
返回值:成功 发送的字符长度
失败 -1;
客户端 自动连接服务器。

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
功能:该函数固定有客户端使用,表示从当前主机向目标
主机发起链接请求。
参数:sockfd 本地socket创建的套接子id
addr 远程目标主机的地址信息。
addrlen: 参数2的长度。
返回值:成功 0
失败 -1;
黏包问题
tcp在通信过程中,数据之间没有边界,接收方不能还原数据。发送方可以发送多次,接收发 ,一次性接送,导致数据不能正常解析的现象。
可以通过以下方法解决
- 长度头(首选):头部 4 字节存消息长度(网络序),先收长度再收对应数据。
- 分隔符:消息末尾加标记,不能出现在消息内容内。
- 固定包长:所有报文长度一致。
注意,用sleep或者usleep只能临时缓解,减缓发送时长,临时性解决
5. UDP 与 TCP 对比
| 对比维度 | UDP | TCP |
|---|---|---|
| 连接方式 | 无连接 | 面向连接(三次握手) |
| 可靠性 | 不可靠,不保证送达 | 可靠,确认 + 重传 |
| 有序性 | 不保证顺序 | 保证按序到达 |
| 传输方式 | 面向报文 | 面向字节流 |
| 头部开销 | 8 字节 | 20~60 字节 |
| 流量/拥塞控制 | 无 | 有 |
| 通信模式 | 单播、广播、多播 | 仅单播 |
| 典型场景 | 音视频、游戏、DNS、QUIC | HTTP、文件传输、数据库连接 |
一句话总结:TCP 追求可靠,UDP 追求高效。选择哪个协议,取决于业务能否容忍丢包,以及是否愿意在应用层自己实现可靠性。