以下是一个简单的 Python Socket 客户端示例,用于连接到指定的服务端,并发送和接收数据:
import socket
# 创建一个客户端 Socket 对象
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置服务端地址和端口号
server_address = ('localhost', 8888)
# 连接到服务端
client_socket.connect(server_address)
# 发送数据到服务端
message = 'Hello, Server!'
client_socket.sendall(message.encode())
# 接收服务端响应的数据
data = client_socket.recv(1024)
print('Received from server: ', data.decode())
# 关闭 Socket 连接
client_socket.close()
说明:
socket.socket(socket.AF_INET, socket.SOCK_STREAM)
创建了一个 IPv4 TCP 客户端 Socket 对象。server_address
设置服务端的 IP 地址和端口号。client_socket.connect(server_address)
建立 Socket 连接到服务端。client_socket.sendall(message.encode())
向服务端发送数据,这里需要将字符串编码成字节流。client_socket.recv(1024)
接收服务端响应的数据,最多读取 1024 字节。client_socket.close()
关闭客户端 Socket 连接。从上面看来socket的客户端发送和接收响应是相当的简单,正常来说也确实如此。但是当发送数据后,服务端不止一次响应,具体有多少次响应不知道,响应内容也没有相关协议可判断是否完成时这个时候就坑的一逼了~
如何保证每次发送数据接收到的都是当前发送数据的应答数据?
如果保证获取完成了当前的所有应答数据?
个人遇到的就是上述2个问题,如果有类似问题的可以接下来继续看,如果没有的那求轻轻放过~
Python中的socket库提供了缓冲区来处理接收数据。当从套接字中读取数据时,这些数据被存储在接收缓冲区中,然后应用程序可以通过调用recv()函数来读取这些数据。
以下是一些有关Python socket接收缓冲区的常见问题和解答:
接收缓冲区的大小是可以配置的,可以使用setsockopt()函数设置套接字选项来更改缓冲区的大小。默认情况下,接收缓冲区大小为8192字节。
可以通过调用select()函数来检查套接字的接收缓冲区中是否有数据。该函数允许应用程序监视多个套接字,并指示哪些套接字准备好读取数据。
如果接收缓冲区已满,新到达的数据将被丢弃。为了避免这种情况,应用程序需要及时读取接收缓冲区中的数据。
可以使用recv()函数来读取接收缓冲区中的数据,并在读取完数据后将缓冲区清空。如果不需要接收缓冲区中的数据,则可以使用recv()函数的MSG_DONTWAIT标志来读取剩余的数据并将其丢弃。
发送数据后就需要接收数据,但是接收数据时可能缓冲区还有大量的数据。因此为了保证接收到的数据是当前发送数据的应答结果,则需要在发送数据之前先清空缓冲区。
清空缓冲区按照上述缓冲区的解释,可以和select结合检查,上代码:
def clear_buff(self):
"""
清空接收缓冲区
设置为socket为非阻塞模式后开始处理
设置超时时间为0.1s
处理完成后,将socket恢复为阻塞模式
"""
try:
socket.setblocking(False)
while True:
ready_socket = select.select([self.eTerm_socket], [], [], 0.1)
if ready_socket and ready_socket[0]:
continue_cmd_recv = socket.recv(4096)
# 执行数据处理,丢弃也好,使用也好,按照业务处理
else:
break
except:
raise
finally:
socket.setblocking(True)
接收内容首先要保证接受的是当前发送数据后的应答结果,其次要保证应答数据接收完整。有了上面清空缓冲区的理解,可知:
def recv_buff(self,cmd_recv):
"""
清空接收缓冲区
设置为socket为非阻塞模式后开始处理
设置超时时间为0.1s
处理完成后,将socket恢复为阻塞模式
Args:
cmd_recv: 指令接收内容(发送数据后第一次接收到的内容)
Returns:指令响应结果
"""
try:
socket.setblocking(False)
while True:
ready_socket = select.select([self.eTerm_socket], [], [], 0.5)
if ready_socket and ready_socket[0]:
continue_cmd_recv = socket.recv(4096)
if cmd_recv:
# 添加换行符来切分多个应答包
cmd_recv += bytes(b'\r')
cmd_recv += continue_cmd_recv[19:]
else:
cmd_recv = continue_cmd_recv
else:
break
except:
raise
finally:
socket.setblocking(True)
return cmd_recv
这样做从效果来看是达到了目的,但是总觉得还有更好的方式……希望大家多多指教~