面试经典:TCP粘包是怎么回事?

前言

关于TCP协议的问题在面试中会经常被问道,尤其是在应届生面试中。

TCP协议是面向连接的可靠性协议。说它可靠并不表示数据信息一定会被对端接受,而是在传输失败后会放弃重传机制并中断连接来通知用户。它提供的只是数据可靠性的传输和故障通知。

回到TCP粘包这个问题上,TCP是数据流传输,数据流是只有起点和终点的字节数据序列,只有输入流和输出流。根本不存在“包”的概念。

那大家常说的粘包的“包”是指什么呢?

其实大家说的是应用层的包,应用层协议规定了包的结构和大小,本质上就是一段数据报文。

具体的包可能像这样

//简简单单 自定义应用层协议
struct Message {
    int packSize;
    int type;
    char buf[100];
};

//http 请求
GET /hello.txt HTTP/1.1
User-Agent: curl/7.16.3 libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3
Host: www.example.com
Accept-Language: en, mi

TCP粘包的原因

在说原因之前我先讲讲粘包的两种情况:

假设有A,B两个包,A包在B包之前

1.接收端接受缓冲区中有A包的一部分

2.接收端接受缓冲区中有A包和B包的一部分

上述情况都属于粘包。

发送端原因:

TCP连接在默认情况下开启Nagle算法优化。当一个连接上有待确认的数据时(也就是发送端没有收到接受端发回来的ACK),此时调用send发送数据,只是将数据填充到发送缓冲区中。等收到ACK后一起发送。

接收端原因:

处理数据不及时,数据都堆积在接收缓冲区中,致使AB两包相连。

如何解决粘包

1.固定包长度。每个包的大小都是一样的。
2.设置特定的结束标志。
3.在包中给定包大小。
例如:(固定前4个字节为包大小)
struct Message {
    int packSize;
    int type;
    char buf[100];
};

http协议就是使用了上述的2,3方法。http使用"\r\n"为结束标识。当为post请求时则有content-Length标识请求体长度。

关于Nagle算法

我再说说nagle算法吧,上面说得比较简略。

Nagle算法的目的是减少广域网中小分组的数目。也就是说尽可能在一次传输中多发送数据,从而减少频繁的网络交互。

/* 
* Return 0, if packet can be sent now without violation Nagle's rules:
* 1. It is full sized      
* 2. Or it contains FIN. (already checked by caller)       
* 3. Or TCP_CORK is not set, and TCP_NODELAY is set.        
* 4. Or TCP_CORK is not set, and all sent packets are ACKed.        
* With Minshall's modification: all sent small packets are ACKed.  
*/   
static inline int tcp_nagle_check(const struct tcp_sock *tp,
                                        const struct sk_buff *skb,
                                     unsigned mss_now, int nonagle)
{
  return skb->len < mss_now &&((nonagle & TCP_NAGLE_CORK) ||
  (!nonagle && tp->packets_out && tcp_minshall_check(tp)));
}    

根据linux源码可看出数据在哪些情况会立即发送:

1.当数据缓冲区数据>=MSS时。(MSS为TCP连接中最大报文长度,收发双方协商通信时每一个报文段所能承载的最大数据长度)

2.数据包包含FIN选项

3.TCP_CORK不设置,TCP_NODELAY选项设置

4.TCP_CORK不设置,收到接受方的ack确认


总结

TCP粘包就是应用层规定好了两个或多个数据包,同时存在于接受缓冲区,致使接收端要进行分包或组合的情况。

粘包情况是普遍存在的,通常通过指定包大小或指定结束标志来区分。

有些场景并不适合使用Nagle算法,像游戏类这种服务要求实时比较高的,就不需要开启。

可使用TCP选项,TCP_NODELAY关闭Nagle算法

最近和几个大学学弟聊天,他们在找实习面试时这种问题还是会经常被问到的,

这些都属于经典面试题,后续准备做一个面试系列,专门讲解一些应届生找工作或实习时遇到的真实面试问题。希望和大家一起进步。

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值