使用GSocketClient对接Telnet时g_input_stream_read_all()阻塞如何解决
问题根因
你出现阻塞的核心原因是误用了g_input_stream_read_all()接口:
- 该接口的设计逻辑是必须读满你传入的指定字节数(你代码里是1024),或者遇到流结束、IO错误时才会返回,只要TCP连接还存活,且服务端没有发送够1024字节数据,接口就会一直阻塞等待数据到达。
- Telnet服务端默认是行缓冲输出,大部分场景下不会一次性发送满1024字节的数据,所以你读完第一个恰好满1024字节的块之后,下一次调用
g_input_stream_read_all()就会进入无限等待,直到连接断开触发流结束才返回。
解决方案
把g_input_stream_read_all()替换为g_input_stream_read()即可,该接口不会等待凑满指定字节数,只要内核接收缓冲区有可用数据就会返回,返回值即为本次实际读到的字节数,返回0代表对端关闭了连接,返回-1代表出现IO错误。
修改后的参考代码如下:
GInputStream* istream = g_io_stream_get_input_stream(G_IO_STREAM(scon)); GOutputStream* ostream = g_io_stream_get_output_stream(G_IO_STREAM(scon)); gssize dlen = 0; gchar buffer[1024]; GError* error = NULL; // 改用g_input_stream_read,有多少读多少 while ((dlen = g_input_stream_read(istream, buffer, 1024, NULL, &error)) > 0) { for (int i = 0; i < dlen; i++) { g_print("%c", buffer[i]); } } if (error != NULL) { // 错误处理逻辑 g_print("读取错误:%s\n", error->message); g_error_free(error); }
额外注意事项
- 如果你是在GTK UI线程中执行上述读取逻辑,同步读仍然会阻塞UI主循环导致界面无响应,建议改用
g_input_stream_read_async()异步IO接口,通过回调处理到达的数据,不会阻塞主线程。 - Telnet协议包含特殊的IAC控制指令,直接打印可能会出现乱码,若要做完整的Telnet客户端需要额外处理协议控制字节。
内容的提问来源于stack exchange,提问作者Pavel Naberezhnev
相关产品推荐
相关产品推荐

