使用Socat运行程序作为服务器时响应顺序错乱且延迟输出问题
问题原因与解决方案:Socat运行C程序服务器时的输出异常
问题描述
你尝试用Socat将一个简单的C程序作为TCP服务器运行,但遇到两个异常:
- 服务器的响应顺序不正确;
- 客户端只有发送完所有数据后,才能收到服务器的响应。
原C程序代码
#include <stdio.h> int main(int argc, char *argv[]){ char buff[64]; char t[10]; printf("Welcome\n"); gets(t); printf(t); printf("\n"); gets(buff); return 0; }
Socat运行时的异常现象
- 服务器端执行命令及输出:
$ socat -v tcp-listen:4444,reuseaddr,fork exec:"./test" > 2018/05/24 10:33:42.102445 length=2 from=0 to=1 a > 2018/05/24 10:33:42.582042 length=2 from=2 to=3 a < 2018/05/24 10:33:42.583721 length=10 from=0 to=9 Welcome a $ socat -v tcp-listen:4444,reuseaddr,fork exec:"./leak" > 2018/05/24 10:39:02.551405 length=7 from=0 to=6 FOOBAR > 2018/05/24 10:39:03.511667 length=5 from=7 to=11 LALA < 2018/05/24 10:39:03.512021 length=15 from=0 to=14 Welcome FOOBAR
- 客户端执行命令及输出:
$ nc 192.168.2.230 4444 FOOBAR LALA Welcome FOOBAR
而直接运行程序时一切正常:
$ ./test Welcome FOOBAR FOOBAR :)
问题根源
核心原因是标准输出(stdout)的缓冲机制随输出目标不同而变化:
- 当程序直接在终端运行时,stdout默认是行缓冲模式——只要输出中包含换行符
\n,就会立即将缓冲内容刷新到终端,所以printf("Welcome\n")会马上显示出来。 - 当通过Socat的
exec选项启动程序时,stdout被关联到管道而非终端,此时stdout会自动切换为全缓冲模式。程序输出的内容会先暂存在内存缓冲中,只有当缓冲被填满、程序退出,或者主动调用刷新函数时,才会一次性将缓冲内容发送给客户端。
这就导致了:
- 服务器的"Welcome"提示被缓冲,直到客户端发送完所有数据、程序执行后续输出操作后,才和其他内容一起被发送;
- 客户端无法实时收到服务器的响应,必须等自己发送完所有数据才能看到结果。
解决方案:关闭标准输出缓冲
在程序的开头添加setbuf(stdout, 0);语句,强制关闭stdout的缓冲,让所有输出内容立即被发送到客户端。
修改后的完整代码
#include <stdio.h> int main(int argc, char *argv[]){ setbuf(stdout, 0); char buff[64]; char t[10]; printf("Welcome\n"); gets(t); printf(t); printf("\n"); gets(buff); return 0; }
修改后重新通过Socat启动服务器,客户端会立即收到"Welcome"提示,输出顺序也会和直接运行程序时完全一致。
内容的提问来源于stack exchange,提问作者sinkmanu
相关产品推荐
相关产品推荐

