You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python socketserver中接收全部连接数据且避免客户端挂起

问题分析

你的问题核心是双向阻塞死锁:服务器一直在循环recv直到客户端关闭连接,而客户端发完数据后立刻调用SSL_read等待服务器回复,两边都卡在等待对方动作的状态,最终导致挂起。


方法1:约定消息长度(最可靠方案)

如果无法提前知道消息长度,可先发送消息的字节长度,让服务器明确接收总量,无需一直等待连接关闭。

客户端修改代码:

char text[] = "Hello world\n";
int len = strlen(text);
// 先发送转换为网络字节序的长度(4字节整数)
uint32_t net_len = htonl(len);
SSL_write(ssl, &net_len, sizeof(net_len));
// 再发送实际数据
SSL_write(ssl, text, len);

// 等待服务器回复并处理
char tmp[20];
int received = SSL_read(ssl, tmp, sizeof(tmp)-1);
if (received > 0) {
    tmp[received] = '\0';
    printf("Server replied: [%s]\n", tmp);
}

服务器修改代码:

class ConnectionHandler(BaseRequestHandler):
    def handle(self):
        # 先接收4字节的长度数据
        len_data = self.request.recv(4)
        if not len_data:
            return
        # 转换为主机字节序
        data_len = int.from_bytes(len_data, byteorder='big')
        # 按指定长度接收数据
        data = b''
        while len(data) < data_len:
            # 每次接收剩余长度和1024的较小值,避免浪费
            tmp = self.request.recv(min(1024, data_len - len(data)))
            if not tmp:
                break
            data += tmp
        print(data.decode())
        
        # 必须发送回复,否则客户端的SSL_read会一直阻塞
        self.request.sendall(b"Message received")

方法2:用分隔符标记消息结束

如果不想处理长度逻辑,可约定一个特殊分隔符(比如"\r\nEND\r\n"),客户端发完数据后追加分隔符,服务器检测到分隔符就停止接收。

客户端修改代码:

// 在消息末尾加上约定的分隔符
char text[] = "Hello world\n\r\nEND\r\n";
SSL_write(ssl, text, strlen(text));

// 等待服务器回复
char tmp[20];
int received = SSL_read(ssl, tmp, sizeof(tmp)-1);
if (received > 0) {
    tmp[received] = '\0';
    printf("Server replied: [%s]\n", tmp);
}

服务器修改代码:

class ConnectionHandler(BaseRequestHandler):
    def handle(self):
        data = b''
        delimiter = b"\r\nEND\r\n"
        while True:
            tmp = self.request.recv(1024)
            if not tmp:
                break
            data += tmp
            # 检测到分隔符则停止接收,截取有效内容
            if delimiter in data:
                data = data.split(delimiter)[0]
                break
        print(data.decode())
        
        // 发送回复
        self.request.sendall(b"Message received")

方法3:客户端发完数据后关闭写方向

如果不想修改协议逻辑,客户端发完数据后可关闭SSL的写方向,告知服务器数据发送完毕,此时服务器的recv会收到空字节,结束循环后再回复客户端。

客户端修改代码:

char text[] = "Hello world\n";
SSL_write(ssl, text, sizeof(text));

// 关闭写方向,通知服务器数据已发送完成
SSL_shutdown(ssl);

// 等待并处理服务器回复
char tmp[20];
int received = SSL_read(ssl, tmp, sizeof(tmp)-1);
if (received > 0) {
    tmp[received] = '\0';
    printf("Server replied: [%s]\n", tmp);
}
// 最后释放SSL资源
SSL_free(ssl);

服务器保持原接收逻辑(需添加回复):

class ConnectionHandler(BaseRequestHandler):
    def handle(self):
        data = b''
        while 1:
            tmp = self.request.recv(1024)
            if not tmp:
                break
            data += tmp 
        print(data.decode())
        
        // 必须发送回复,否则客户端的SSL_read会一直阻塞
        self.request.sendall(b"Message received")

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 14:35:16