【Python基础入门】什么是socket?socket缓冲区与阻塞!
老男孩IT教育
常见问题
2021年10月27日 18:34
什么是socket?socket的原意是“插座”,在计算机通信领域,socket被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。
什么是socket?socket的原意是“插座”,在计算机通信领域,socket被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。
通过socket这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。我们把插头插到插座上就能从电网获得电力供应,同样,为了与远程计算机进行数据传输,需要连接到因特网,而socket 就是用来连接到因特网的工具。


socket缓冲区与阻塞
socket缓冲区
每个socket被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区。write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器。一旦将数据写入到缓冲区,函数就可以成功返回,不管它们有没有到达目标机器,也不管它们何时被发送到网络,这些都是TCP协议负责的事情。
TCP协议独立于write()/send()函数,数据有可能刚被写入缓冲区就发送到网络,也可能在缓冲区中不断积压,多次写入的数据被一次性发送到网络,这取决于当时的网络情况、当前线程是否空闲等诸多因素,不由程序员控制。read()/recv() 函数也是如此,也从输入缓冲区中读取数据,而不是直接从网络中读取。

这些I/O缓冲区特性可整理如下:
I/O缓冲区在每个TCP套接字中单独存在;
I/O缓冲区在创建套接字时自动生成;
即使关闭套接字也会继续传送输出缓冲区中遗留的数据;
关闭套接字将丢失输入缓冲区中的数据。
输入输出缓冲区的默认大小一般都是8K!
阻塞模式
对于TCP套接字(默认情况下),当使用send() 发送数据时:
(1) 首先会检查缓冲区,如果缓冲区的可用空间长度小于要发送的数据,那么send()会被阻塞(暂停执行),直到缓冲区中的数据被发 送到目标机器,腾出足够的空间,才唤醒send()函数继续写入数据。
(2) 如果TCP协议正在向网络发送数据,那么输出缓冲区会被锁定,不允许写入,send()也会被阻塞,直到数据发送完毕缓冲区解锁,send()才会被唤醒。
(3) 如果要写入的数据大于缓冲区的最大长度,那么将分批写入。
(4) 直到所有数据被写入缓冲区send()才能返回。
当使用recv()读取数据时:
(1) 首先会检查缓冲区,如果缓冲区中有数据,那么就读取,否则函数会被阻塞,直到网络上有数据到来。
(2) 如果要读取的数据长度小于缓冲区中的数据长度,那么就不能一次性将缓冲区中的所有数据读出,剩余数据将不断积压,直到有recv()函数再次读取。
(3) 直到读取到数据后recv()函数才会返回,否则就一直被阻塞。
TCP套接字默认情况下是阻塞模式,也是最常用的。当然你也可以更改为非阻塞模式,后续我们会讲解。
TCP的粘包问题
上节我们讲到了socket缓冲区和数据的传递过程,可以看到数据的接收和发送是无关的,read()/recv()函数不管数据发送了多少次,都会尽可能多的接收数据。也就是说,read()/recv()和write()/send() 的执行次数可能不同。
例如,write()/send()重复执行三次,每次都发送字符串"abc”,那么目标机器上的 read()/recv()可能分三次接收,每次都接收"abc";也可能分两次接收,第一次接收"abcab",第二次接收"cabc";也可能一次就接收到字符串"abcabcabc"。
这就是数据的“粘包”问题,客户端发送的多个数据包被当做一个数据包接收。也称数据的无边界性,read()/recv()函数不知道数据包的开始或结束标志(实际上也没有任何开始或结束标志),只把它们当做连续的数据流来处理。
学Python,认准老男孩IT教育!老男孩教育Python培训采用线上、线下相结合的方式,科学的教学方法,无论学员选择哪一种授课方式,均能学到真知识!
推荐阅读:
老男孩教育专注IT教育10余年,只培养IT技术精英
全国免费咨询电话(渠道合作):400-609-2893











