TCP粘包现象

我在暑假做课设的时候要做一个文件传输的功能,于是我有如下设计:
 
发送端A:

char szbuf[MAX_LEN];

while (1)
{
/* 将前1个字节作为消息的标志位(标志该包是否是文件的结尾) */
/* 将文件读入(szbuf+1) */
send(....);
}
       
接收端B:

char szbuf[MAX_LEN];

while (1)
{
recv(....);
/* 将收到的数据写入文件 */
if(/* 标志位说明是文件结尾 */)
{
/* 关闭文件 */
}
}
 
假设我们有一个文本文件,内容都是a
那么按我们的预期一个包的内容应该是 1 aaaaaaaaaa(假设0表示文件结尾,1表示文件内容,每次发送10个字节的文件内容)
但是有的时候在接收端会读到第一个字节为 a的情况,导致判断的时候逻辑出错。为什么呢?
 
上网查了以后,得到以下结论:
由于TCP在发送包的时候是基于流式的,所以会出现以下几种情况:
 
1.假设发送端连续发送两个 1 aaaaaaaaaa 包,那么在接收端的缓冲区中会连续存储着1aaaaaaaaaa1aaaaaaaaaa接收端先后两次按照预期的从缓冲区中读出11个字节,得到1aaaaaaaaaa
 
2.发送端在发送一个 1aaaaaaaaaa的包时,可能会是分两次发送的,也就是说可能第一次只发送了 1 aaaaa的数据,而第二次将剩下的 5个a与第二个包并为 aaaaa 1 aaaaaaaaaa然后再发送。由于TCP基于流式的性质,那么以上发送的 1 aaaaaaaaaa1aaaaaaaaaa会被先后写入接收端的缓冲区,合并成1aaaaaaaaaa1aaaaaaaaaa。然后接收端先后两次按照预期的从缓冲区中读出11个字节1aaaaaaaaaa
 
以上说的是理想情况下的发送与接收,实际情况下,可能会出现第3种情况:
发送端在发送一个 1aaaaaaaaaa的包时,分两次发送的,第一次发送了 1 aaaaa的数据。正当此时,接收端去读缓冲区的时候发现缓冲区中只有6个字节的数据,那么接收端就会只读6个字节上来。那么在下一个包 aaaaa 1 aaaaaaaaaa 到达后,接收端如果还是读11个字节的话就会得到aaaaa1aaaaa的结果。也就是我们之前遇到的问题。
 
那么有什么方法可以解决我们这个问题呢?
 
我总结的有两个:
1.既然是文件发送,整个文件是连续的,那么我在发送的时候不需要标志位,接受端不论每次收到几个字节都一股脑地写入文件,在发送完成的时候,由发送端closesocket就可以。
这样实现确实是可以做到不发生错误,但是有一个问题,如果我在发送TCP包的时候确实需要一些标志状态的标志位呢?我在网上找到了另一种方法
2.每次在接收端接受的时候判断收到的字节是否为预期的大小,如果不是,那么再次recv剩下的大小,直到接收端收到预期的大小为止。这样就可以保证每次发送端发出了什么信息,接收端也能收到同样的信息。
 
看了以上的解释后,我再分享一个问题:
我在使用我最初的设计(也就是最前面的那两段会出错的伪码)写出代码后,在两台机子上测试,一台是我家里7、8年前买的老古董电脑,一台是我现在用的本本,此时会有一个神奇的情况,如果是我家的老电脑向我的本本发的时候,会出现逻辑混乱,挂了……然而要是用我的本本向老电脑发文件的时候,却一点问题没有~为什么呢~~?(大家先想一下再看下我的想法)
我的想法是这样的:如果是本本向老电脑发时,由于send速度快些,老电脑recv慢些,所以recv的时候缓冲区中都是充裕的,不会出现那种读不全的情况;而老电脑向本本发的时候,由于send慢,recv快,所以可能在本本recv的时候,老电脑还没send完,这样就会出现前面说的第3中情况。(个人见解,如果异议,敬候……)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值