这周在新的产品版本上线后,发现监控日志总是会报recv()返回error,并且errno是131(ECONNRESET)。查了一下man手册,发现并没有说recv()会返回ECONNRESET,于是自己便打算一探究竟。想到最近正在学习Dtrace,于是便写了下面这个简单脚本(check_recv.d):
#!/usr/sbin/dtrace -qs
syscall::recv:return
/(int)arg0 <=0 && pid == $1/
{
printf("recv return: tid=%d, arg0=%d, errno=%d\n", tid, arg0, errno);
}第四行是触发探针条件:当recv返回0或者-1并且进程号等于输入监控的进程号。
第六行是输出:线程ID,recv()返回值,errno。
使用方法 :check_recv.d 19771(监控进程号)
通过运行脚本,我发现其实recv()返回的是0,而errno也是0,那么为什么监控日志会输出errno是131呢?我又查了一下这个版本新加的代码,发现了下面的逻辑:
if (recv() <= 0)
{
log(errno)
}原来在recv()返回0时,也会输出errno。而在recv()返回0时,是不会更新errno的值,只有在recv()返回-1时,才会更新errno的值。所以现在监控日志里的errno其实是以前某个系统调用错误时设置的errno。所以代码应该改为:
if (recv() < 0)
{
log(errno)
}问题解决!

本文介绍了一个recv()函数返回值误判的问题,通过Dtrace脚本定位到recv()返回0时误将之前的errno值记录下来的原因,并给出了正确的代码实现。
3188

被折叠的 条评论
为什么被折叠?



