c++理论篇(一) ——浅谈tcp缓存与tcp的分包与粘包

介绍

在网络通讯中,Linux系统为每一个socket创建了接收缓冲区与发送缓冲区,对于TCP协议来说,这两个缓冲区是必须的.应用程序在调用send/recv函数时,Linux内核会把数据从应用进程拷贝到socket的发送缓冲区中,应用程序在调用recv/read函数时,内核把接收缓冲区中的数据拷贝到应用进程的接收缓冲区中.

我们也可以查看socke缓冲区的大小:

cpp 复制代码
int bufsize=0;
socket_t optlen=sizeof(bufsize);
getsockopt(sockfd,SOL_SOCKET,SO_SNDBUF,&bufsize,(socklen_t*)&optlen); //获取发送缓冲区大小
cout<<"send buffer size:"<<bufsize<<endl; //打印

getsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&bufsize,(socklen_t*)&optlen); //获取接收缓冲区大小
cout<<"recv buffer size:"<<bufsize<<endl; //打印

一些思考

  1. send函数会阻塞吗

    会,如果发送端的发送缓冲区与接收端的接收缓冲区已满,那么send函数会阻塞,直到缓冲区有空闲位置。

  2. 向socket发送数据后,如果关闭socket,对端会接收到数据吗

    会,因为socket缓冲区是双向的,发送端和接收端都会缓冲数据

Nagle算法

前言

在TCP协议中,无论发送多少数据,都要在数据前面加上协议头,同时,对方收到数据后,也需要回复ACK表示确认。为了尽可能的利用网络带宽,TCP希望每次都能够以MSS(Maximum Segment Size,最大报文长度)的数据块来发送数据。

Nagle算法的目的

Nagle算法就是为了尽可能发送大块的数据,避免网络中充斥着小数据块。

Nagle算法的工作原理

Nagle算法的定义是:任意时刻,最多只能有一个未被确认的小段,小段是指小于MSS的数据块,未被确认是指一个数据块发送出去后,没有收到对端回复的ACK。

举个例子:发送端调用send()函数将一个int型数据(称之为A数据块)写入到socket中,A数据块会被马上发送到接收端,接着,发送端又调用send()函数写入一个int型数据(称之为B数据块),这时候,A块的ACK没有返回(已经存在了一个未被确认的小段),所以B块不会立即被发送,而是等A块的ACK返回之后(大概40ms)才发送。

ACK延迟机制

TCP协议中不仅仅有Nagle算法,还有一个ACK延迟机制:当接收端收到数据之后,并不会马上向发送端回复ACK,而是延迟40ms后再回复,它希望在40ms内接收端会向发送端回复应答数据,这样ACK就可以和应答数据一起发送,把ACK捎带过去。

Nagle的缺点与解决方案

如果TCP连接的一端启用了Nagle算法,另一端启用了ACK延时机制,而发送的数据包又比较小,则可能会出现这样的情况:发送端在等待上一个包的ACK,而接收端正好延迟了此ACK,那么这个正要被发送的包就会延迟40ms。

解决方案

开启TCP_NODELAY选项,这个选项的作用就是禁用Nagle算法。

CPP 复制代码
#include <netinet/tcp.h>   // 注意,要包含这个头文件。
int opt = 1;   
setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY,&opt,sizeof(opt));

对时效要求很高的系统,例如联机游戏、证券交易,一般会禁用Nagle算法。

Tcp的分包与粘包

  • 分包:tcp报文的大小缺省是1460字节,如果发送缓冲区中的数据超出了1460字节,那么Tcp将会拆分多个包来发送,如果接收方及时从接收缓冲区中取走了数据,看起来就像是接收了多个报文。

  • 粘包:tcp接收到数据后,有序的放在缓冲区中,由于数据与数据之间不存在分隔符的说法,如果接收方没有及时的从缓冲区中取走数据,看起来就会和粘起来一样。

解决方案

为了解决上述出现的问题,我们对发送报文与接收报文的方式进行了修改。

  • 发送端:先发送报文长度,再发送报文内容。
  • 服务端:先接收报文长度,再接收报文内容。

结语

这一篇文章主要是为下一篇网络编程的服务端与客户端编写做一个引子,介绍一些有关网络编程的基本知识,因为下一篇文章将会给大家介绍在c++网络编程中有关服务端与客户端的编写,本文只做一些理论介绍,大家下篇见!

相关推荐
Once_day11 分钟前
C++之《程序员自我修养》读书总结(1)
c语言·开发语言·c++·程序员自我修养
Trouvaille ~21 分钟前
【Linux】TCP Socket编程实战(一):API详解与单连接Echo Server
linux·运维·服务器·网络·c++·tcp/ip·socket
liann11922 分钟前
3.1_网络——基础
网络·安全·web安全·http·网络安全
偷吃的耗子26 分钟前
【CNN算法理解】:CNN平移不变性详解:数学原理与实例
人工智能·算法·cnn
坚果派·白晓明33 分钟前
在鸿蒙设备上快速验证由lycium工具快速交叉编译的C/C++三方库
c语言·c++·harmonyos·鸿蒙·编程语言·openharmony·三方库
独行soc34 分钟前
2026年渗透测试面试题总结-17(题目+回答)
android·网络·安全·web安全·渗透测试·安全狮
辣香牛肉面35 分钟前
Wireshark v4.6.2 开源免费网络嗅探抓包工具中文便携版
网络·测试工具·wireshark
全栈工程师修炼指南38 分钟前
Nginx | stream 四层反向代理:SSL、PREREAD 阶段模块指令浅析与实践
运维·网络·网络协议·nginx·ssl
小镇敲码人40 分钟前
深入剖析华为CANN框架下的Ops-CV仓库:从入门到实战指南
c++·python·华为·cann
科技块儿43 分钟前
利用IP查询在智慧城市交通信号系统中的应用探索
android·tcp/ip·智慧城市