You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Python Socket连接成功但无数据传输问题求助

问题描述

我刚开始学习Python Socket编程,尝试通过Python Socket与Raspberry Pi 3进行数据收发。服务端程序运行在Raspberry Pi上,客户端程序运行在我的Ubuntu系统笔记本上,二者处于同一WiFi网络。程序启动后客户端能够成功连接服务端,但没有数据传输,客户端和服务端均无任何响应;不过在同一设备上运行两端程序时一切正常。

补充说明:当我在客户端按下Ctrl + C后,服务端似乎会在断开连接前发送部分数据。

客户端代码

import socket
HOST = '172.16.31.51'
PORT = 5000
BUFSIZ = 1024
if __name__ == '__main__':
    client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    host = input("Enter hostname [%s]: " %HOST) or HOST
    port = input("Enter port [%s]: " %PORT) or PORT
    sock_addr = (host, int(port))
    client_sock.connect(sock_addr)
    payload = 'GET TIME'
    try:
        while True:
            client_sock.send(payload.encode('utf-8'))
            data = client_sock.recv(BUFSIZ)
            print(repr(data))
            more = input("Want to send more data to server[y/n]:")
            if more.lower() == 'y':
                payload = input("Enter payload: ")
            else:
                break
    except KeyboardInterrupt:
        print("Exited by user")
    client_sock.close()

服务端代码

import socket
from time import ctime
PORT = 5000
BUFSIZ = 1024
ADDR = ('', PORT)
if __name__ == '__main__':
    server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    server_socket.bind(ADDR)
    server_socket.listen(5)
    server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
    while True:
        print('Server waiting for connection...')
        client_sock, addr = server_socket.accept()
        print('Client connected from: ', addr)
        while True:
            data = client_sock.recv(BUFSIZ)
            if not data or data.decode('utf-8') == 'END':
                break
            print("Received from client: %s" % data.decode('utf-8'))
            print("Sending the server time to client: %s" %ctime())
            try:
                client_sock.send(bytes(ctime(), 'utf-8'))
            except KeyboardInterrupt:
                print("Exited by user")
        client_sock.close()
    server_socket.close()
问题分析与解决方案

你的代码在本地设备运行正常,但跨设备通信时卡住,核心原因是TCP的Nagle算法导致小数据包被缓冲延迟发送,加上跨网络的传输特性,使得客户端发送的数据无法及时到达服务端,两边都卡在recv()调用上。另外服务端的SO_REUSEADDR设置位置也有问题,下面是具体的修复和调试建议:

1. 禁用Nagle算法,确保数据即时发送

在客户端连接成功后,添加一行代码禁用TCP_NODELAY选项,这样客户端发送的小数据包会立即发送到服务端,不会被系统缓冲:

client_sock.connect(sock_addr)
# 添加这行代码,禁用Nagle算法
client_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

2. 修正服务端SO_REUSEADDR的设置位置

SO_REUSEADDR选项用于允许端口复用,应该在bind()之前设置,否则可能无法生效:

server_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 将setsockopt移到bind之前
server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
server_socket.bind(ADDR)
server_socket.listen(5)

3. 检查Raspberry Pi的防火墙配置

虽然你能成功建立连接,但仍需确认Pi上的5000端口是否允许双向通信:

  • 临时关闭防火墙测试:
    sudo ufw disable
    
  • 测试正常后,重新开启防火墙并开放端口:
    sudo ufw enable
    sudo ufw allow 5000/tcp
    

4. 调试辅助建议

可以在代码中添加打印语句,帮助你确认数据的收发状态:

  • 在客户端send()后添加打印:
    client_sock.send(payload.encode('utf-8'))
    print(f"已发送数据: {payload}")
    
  • 在服务端recv()后添加打印:
    data = client_sock.recv(BUFSIZ)
    if not data or data.decode('utf-8') == 'END':
        break
    print(f"收到原始数据: {data}")
    print("Received from client: %s" % data.decode('utf-8'))
    

完成以上修改后,跨设备的Socket数据收发应该就能正常工作了。

内容的提问来源于stack exchange,提问作者Sparsh Kumar

火山引擎 最新活动