python socket tcp客户端接收完整数据

以下是一个简单的 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()

说明:

  1. socket.socket(socket.AF_INET, socket.SOCK_STREAM) 创建了一个 IPv4 TCP 客户端 Socket 对象。
  2. server_address 设置服务端的 IP 地址和端口号。
  3. client_socket.connect(server_address) 建立 Socket 连接到服务端。
  4. client_socket.sendall(message.encode()) 向服务端发送数据,这里需要将字符串编码成字节流。
  5. client_socket.recv(1024) 接收服务端响应的数据,最多读取 1024 字节。
  6. client_socket.close() 关闭客户端 Socket 连接。

从上面看来socket的客户端发送和接收响应是相当的简单,正常来说也确实如此。但是当发送数据后,服务端不止一次响应,具体有多少次响应不知道,响应内容也没有相关协议可判断是否完成时这个时候就坑的一逼了~

如何保证每次发送数据接收到的都是当前发送数据的应答数据?

如果保证获取完成了当前的所有应答数据?

个人遇到的就是上述2个问题,如果有类似问题的可以接下来继续看,如果没有的那求轻轻放过~

清空接收缓冲区

接收缓冲区

Python中的socket库提供了缓冲区来处理接收数据。当从套接字中读取数据时,这些数据被存储在接收缓冲区中,然后应用程序可以通过调用recv()函数来读取这些数据。

以下是一些有关Python socket接收缓冲区的常见问题和解答:

  1. 接收缓冲区的大小是多少?

接收缓冲区的大小是可以配置的,可以使用setsockopt()函数设置套接字选项来更改缓冲区的大小。默认情况下,接收缓冲区大小为8192字节。

  1. 如何检查接收缓冲区中是否有数据?

可以通过调用select()函数来检查套接字的接收缓冲区中是否有数据。该函数允许应用程序监视多个套接字,并指示哪些套接字准备好读取数据。

  1. 如果接收缓冲区已满,会发生什么?

如果接收缓冲区已满,新到达的数据将被丢弃。为了避免这种情况,应用程序需要及时读取接收缓冲区中的数据。

  1. 如何清空接收缓冲区?

可以使用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)

接收完整内容

接收内容首先要保证接受的是当前发送数据后的应答结果,其次要保证应答数据接收完整。有了上面清空缓冲区的理解,可知:

  1. socket.recv,接收数据后就从缓冲区移除了,那只需要循环接收下去就可以接受完整的内容;
  2. 无论如何socket.sendall发送数据后,至少有一次应答,所以第一次完全可以在阻塞模式下线接收内容,然后在循环接收;
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

这样做从效果来看是达到了目的,但是总觉得还有更好的方式……希望大家多多指教~

你可能感兴趣的:(python)