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++网络编程中有关服务端与客户端的编写,本文只做一些理论介绍,大家下篇见!

相关推荐
申阳21 小时前
Day 6:04. 基于Nuxt开发博客项目-LOGO生成以及ICON图标引入
前端·后端·程序员
硅胶人21 小时前
[prowlarr][radarr][sonarr][qBitorrent]套件打造家庭影音中心
后端
Victory_orsh21 小时前
“自然搞懂”深度学习(基于Pytorch架构)——010203
人工智能·pytorch·python·深度学习·神经网络·算法·机器学习
翻斗花园牛图图-21 小时前
Linux网络——传输层协议UDP&&TCP
网络
一叶之秋141221 小时前
Linux基本指令
linux·运维·服务器
CoovallyAIHub21 小时前
突破360°跟踪极限!OmniTrack++:全景MOT新范式,HOTA指标狂飙43%
深度学习·算法·计算机视觉
JavaGuide21 小时前
OPPO 后端校招面试,过于简单了!
java·后端
煤球王子21 小时前
学而时习之:C++中的字符串
c++
码割机21 小时前
Linux服务器安装jdk和maven详解
java·linux·maven
yeapT21 小时前
网络传输协议的介绍——SSE
网络·websocket·http