Python Socket 套接字通信基础与粘包问题解析
本文详细解析Python中Socket套接字的原理与实现,涵盖基于TCP协议的简单通信代码示例。重点探讨了阻塞模式下的同步问题、数据发送非空判断以及接收超过1024字节时的粘包现象,并结合subprocess模块实现服务端命令响应机制,为后续解决粘包问题奠定基础。
Socket概念与原理
首先介绍Socket的概念。
Socket在操作系统架构中位于应用层与传输层之间,属于一种抽象接口。它提供了一组相对简单的操作方式,主要用于接收数据,并将接收到的数据传递给操作系统处理。
既然可以直接与操作系统交互,为何还需要Socket?这种想法存在误区。
操作系统的底层接口实际上非常复杂且难以直接使用。如果开发者直接通过操作系统接口进行数据交换,过程将极其繁琐。因此,开发者需要一种中间机制来简化这一过程,Socket(套接字)应运而生。它的核心作用是对操作系统间的数据交换进行高度封装和简化,从而降低开发难度。
Python Socket基础通信实现
利用Socket可以实现基础的通信功能。
Python内置了socket模块,利用该模块可以方便地实现基于TCP协议的简单通信。
#基于切换连接的循环通信
import socket #首先我们在文件中导入socket 模块
phone = socket.socket() #实例化一个对象
phone.bind(('127.0.01',8765))#bind是存放ip地址的(这里存放的是本地的IP地址)
phone.listen(5)#可以设置连接的个数,
while 1:#循环等待连接
conn,adds = phone.accept()
while 1:#要循环聊天我们要重复接收发送
try: #异常处理
receives_commands = conn.recv(1024) #接收命令请求,最多接收1024字节当然你也可以调整
receivse_commands = receives_commands.decode('utf-8')#网络传输是以字节的形势的所以我们要进行解码
print(f'来自客户端的消息{receives_commands}') #打印消息
if receives_commands.upper(0 == 'Q':break #正常结束
dispatch_orders = inport('请输入:').strip().encode('utf-8')
conn.send(dispatch_orders)
except ConnectionResetError:#客户端异常结束
print('客户端终端')
break
conn.close() #关闭连接
phone.close#关闭服务端
#客户端
import socket
phone = socket.socket()
phone.connect(('127.0.01',8765)) #连接服务端地址
while 1:
dispatch_orders = inport('请输入:').strip().encode('utf-8')#发送请求
if not dispatch_orders:print('不能为空')#不能为空
phone.send(dispatch_orders) #发送
if dispatch_orders.upper() ==b'Q':#正常退出
break
receives_commands = phone.recv(1024)#接收服务端的回执
receives_commands = receives_commands.decode('utf-8')#解码
print(f'来自客户端的消息{receives_commands}') #打印
phone.close()#关闭客户端
接下来,我们将通过Socket构建一个简单的通信链接循环。
通信中的阻塞与非空处理
在实现过程中,有几个关键点需要注意。
首先是阻塞问题。当服务器和客户端均处于阻塞模式时,accept和recv操作会导致双方同步等待,即一方发送或接收时另一方必须同步响应,否则程序会陷入静止状态。这种同步阻塞机制在逻辑上是不合理的,可能导致程序行为异常。
其次,在设计通信逻辑时,必须确保发送的数据不为空。如果发送内容为空,服务端将无法接收到有效消息。因此,代码中需要加入非空判断逻辑。此外,当接收到的数据超过1024字节时,会出现何种情况?
粘包现象与subprocess模块应用
下面针对上述问题进行解答。
为此,我们需要引入操作系统相关的模块。
在Python中,subprocess模块专门用于与cmd命令行进行交互。
obj = subprocess.Popen('dir',#实例化对象括号内第一个参数就是我们的cmd命令行的命令,这里我们写的是dir显示文件夹中内容
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
print(obj.stdout.read().decode('gbk')) # 正确命令
print(obj.stderr.read().decode('gbk')) # 错误命令
基于此,我们可以构建一个服务端响应客户端命令的机制。
import socket
import subprocess
phone = socket.socket()
phone.bind(('127.0.01',8695))
phone.listen(5)
while 1:
conn,adds = phone.accept()
while 1:
try:
receives_commands = conn.recv(1024)
if receiver_commands ==b'Q':break
#obj = subprocess.Popen(Receiving_instructiors,
# shell= True,
#stdout = subprocess.PIPE,
#stderr = subprocess.PIPE
)
obj = subprocess.Popen(receives_commands.decode('utf-8')#动态的传入命令
shell = True
stdout = subprocess.PIPE
stderr = subprocess.PIPE
)
# print(obj.stdout.read().decode('gbk')) # 正确命令
# print(obj.stderr.read().decode('gbk')) # 错误命令
ret = obj.stodut.read()+obj.stderr.read()#将产生的内容进行拼接
conn.send(ret)
except ConnectionResetError:
print('客户端终端')
break
conn.close()
phone.close()
import socket
phone = socket.socket()
phone.connect(('127.0.01',8695))
while 1:
dispatch_orders = inport('请输入命令:').strip().encode('utf-8')
if not dispatch_orders:print('输入不能为空')
phone.send(dispatch_orders)
if dispatch_orders.upper() ==b'Q':break
receives_commands = phone.recv(1024)
receives_commands = receives_commands.decode('utf-8')
print(f'来自客户端的消息{receives_commands}')
phone.close()
然而,这里会出现一个问题:当输入的help命令长度超过1024字节时,该如何处理?
另一个问题是,当输入下一条命令时,可能会接收到上一条命令未传输完成的部分数据,这种现象被称为“粘包”。
那么,造成粘包的原因是什么?
如何解决粘包问题?
这些问题的具体解决方案将在后续章节中详细讲解。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













