Socket通信问题:分段发送命令结果后服务端无响应
问题根源
你的代码卡壳的核心原因是TCP是无边界的流式协议:服务端用while True循环接收数据,只有当recv()返回空(也就是客户端断开连接)才会停止,但客户端发送完所有分段后并没有关闭连接,服务端就会一直阻塞在recv()调用上,永远出不了循环,自然看不到任何输出。
两种可行的解决办法
针对大结果的分段传输,这里给你两种常用的实现方案:
方案一:先传结果长度,再传数据
先让客户端把结果的总字节数发给服务端,服务端知道要收多少数据后,就可以精准接收,不会一直等。
服务端修改后代码
import socket HOST = "填你的服务器IP" PORT = 填你的端口号 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: print("[+] Waiting for incoming connections") s.bind((HOST, PORT)) s.listen() conn, addr = s.accept() print(f"[+] Connected by {addr}") while True: command = input(">>> ") conn.send(command.encode('utf-8')) # 先收结果的字节长度(用4字节存储,大端模式跨平台兼容) len_bytes = conn.recv(4) if not len_bytes: break total_len = int.from_bytes(len_bytes, byteorder='big') # 按长度接收完整结果 result = b"" while len(result) < total_len: # 每次收剩下的长度和4096中较小的那个,避免多收 chunk = conn.recv(min(4096, total_len - len(result))) if not chunk: break result += chunk print(result.decode())
客户端修改后代码
import socket import subprocess HOST = "填你的服务器IP" PORT = 填你的端口号 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) while True: command = s.recv(1024).decode('utf-8') result = subprocess.getoutput(command) result_bytes = result.encode('utf-8') # 先把结果的字节长度发过去(4字节大端) s.send(len(result_bytes).to_bytes(4, byteorder='big')) # 分段发送实际数据 chunk_size = 4096 for i in range(0, len(result_bytes), chunk_size): s.send(result_bytes[i:i + chunk_size])
方案二:用特殊标记表示传输结束
客户端发完所有数据后,再发一个提前约定好的特殊标记,服务端收到这个标记就停止接收。
服务端修改后代码
import socket HOST = "填你的服务器IP" PORT = 填你的端口号 # 自定义一个不会出现在正常结果里的结束标记 END_SIGNAL = b"<__CMD_RESULT_END__>" with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: print("[+] Waiting for incoming connections") s.bind((HOST, PORT)) s.listen() conn, addr = s.accept() print(f"[+] Connected by {addr}") while True: command = input(">>> ") conn.send(command.encode('utf-8')) result = b"" while True: data = conn.recv(4096) if END_SIGNAL in data: # 把标记前面的内容拼进去,然后停止循环 result += data.split(END_SIGNAL)[0] break result += data if not data: break print(result.decode())
客户端修改后代码
import socket import subprocess HOST = "填你的服务器IP" PORT = 填你的端口号 END_SIGNAL = b"<__CMD_RESULT_END__>" with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((HOST, PORT)) while True: command = s.recv(1024).decode('utf-8') result = subprocess.getoutput(command) result_bytes = result.encode('utf-8') # 分段发送数据 chunk_size = 4096 for i in range(0, len(result_bytes), chunk_size): s.send(result_bytes[i:i + chunk_size]) # 发送结束标记告诉服务端数据传完了 s.send(END_SIGNAL)
注意点
- 方案一的4字节长度最多能支持约4GB的数据,足够绝大多数场景使用;如果需要更大的容量,可以换成8字节。
- 方案二的结束标记一定要选不会在正常命令输出里出现的内容,不然会提前终止接收,导致结果不完整。
内容的提问来源于stack exchange,提问作者cihan
相关产品推荐
相关产品推荐

