TCP套接字--阻塞模式和粘包问题
2017-09-14 20:20
295 查看
阻塞模式
对于TCP套接字(默认情况下),当使用 write()/send() 发送数据时:1) 首先会检查缓冲区,如果缓冲区的可用空间长度小于要发送的数据,那么 write()/send() 会被阻塞(暂停执行),直到缓冲区中的数据被发送到目标机器,腾出足够的空间,才唤醒 write()/send() 函数继续写入数据。
2) 如果TCP协议正在向网络发送数据,那么输出缓冲区会被锁定,不允许写入,write()/send() 也会被阻塞,直到数据发送完毕缓冲区解锁,write()/send() 才会被唤醒。
3) 如果要写入的数据大于缓冲区的最大长度,那么将分批写入。
4)
4000
直到所有数据被写入缓冲区 write()/send() 才能返回。
当使用 read()/recv() 读取数据时:
1) 首先会检查缓冲区,如果缓冲区中有数据,那么就读取,否则函数会被阻塞,直到网络上有数据到来。
2) 如果要读取的数据长度小于缓冲区中的数据长度,那么就不能一次性将缓冲区中的所有数据读出,剩余数据将不断积压,直到有 read()/recv() 函数再次读取。
3) 直到读取到数据后 read()/recv() 函数才会返回,否则就一直被阻塞。
这就是TCP套接字的阻塞模式。所谓阻塞,就是上一步动作没有完成,下一步动作将暂停,直到上一步动作完成后才能继续,以保持同步性。
TCP套接字默认情况下是阻塞模式,也是最常用的。当然你也可以更改为非阻塞模式。
TCP粘包问题和数据无界性
上面讲到了socket缓冲区和数据的传递过程,可以看到数据的接收和发送是无关的,read()/recv()函数不管数据发送了多少次,都会尽可能多的接收数据。也就是说,read()/recv() 和 write()/send() 的执行次数可能不同。
例如,write()/send() 重复执行三次,每次都发送字符串"abc",那么目标机器上的 read()/recv() 可能分三次接收,每次都接收"abc";也可能分两次接收,第一次接收"abcab",第二次接收"cabc";也可能一次就接收到字符串"abcabcabc"。
假设我们希望客户端每次发送一位学生的学号,让服务器端返回该学生的姓名、住址、成绩等信息,这时候可能就会出现问题,服务器端不能区分学生的学号。例如第一次发送 1,第二次发送 3,服务器可能当成 13 来处理,返回的信息显然是错误的。
这就是数据的“粘包”问题,客户端发送的多个数据包被当做一个数据包接收。也称数据的无边界性,read()/recv() 函数不知道数据包的开始或结束标志(实际上也没有任何开始或结束标志),只把它们当做连续的数据流来处理。
相关文章推荐
- 网络编程与并发-TCP/UDP套接字、粘包问题、Socket编程、并发编程、FTP作业
- Tcp流套接字两个需要注意的问题:粘包和包分段
- 网络编程与并发-TCP/UDP套接字、粘包问题、Socket编程、并发编程、FTP作业
- TCP流式套接字的阻塞模式编程
- socket缓冲区及阻塞模式/粘包问题/数据的无边界性
- 解决TCP网络传输“粘包”问题
- golang中tcp socket粘包问题和处理
- Android TCP通信的简单实例以及常见问题[超时/主线程阻塞]
- tcp粘包问题(封包)
- TCP粘包问题
- TCP/IP-----------tcp粘包问题
- TCP粘包问题的解决
- TCP粘包问题的分析与解决
- 解决TCP网络传输“粘包”问题
- Socket编程实践(5) --TCP粘包问题与解决
- Netty5入门学习笔记002-TCP粘包/拆包问题的解决之道(上)
- Netty实践(二):TCP拆包、粘包问题
- TCP粘包问题解决
- Netty系列-TCP粘包拆包问题
- libcurl使用easy模式阻塞卡死等问题的完美解决---超时设置