如何获取已断开连接的socket的对端连接信息?
解决方案
getpeername()返回ENOTCONN是符合POSIX标准的默认行为:TCP连接触发ECONNRESET后,内核会立即将socket状态置为关闭,getpeername()仅支持在ESTABLISHED状态的socket上正常返回对端信息。
以下是不需要大规模修改现有代码、也不用自行维护全量socket映射表的可行方案:
- 方案1:连接建立时轻量缓存对端信息
仅需要在connect()(客户端)或accept()(服务端)返回成功的位置,新增一行获取对端信息的逻辑,将数据和socket文件描述符绑定即可,不需要修改现有业务处理流程,侵入性极低。
Linux环境下可以直接用setsockopt()的自定义扩展参数缓存,或者用fd作为key存入进程内的轻量哈希表,仅在连接创建和销毁时更新即可。 - 方案2:读取系统proc文件系统获取历史连接信息
Linux环境下只要socket文件描述符还未被close()释放,哪怕连接已经断开,也可以从/proc/net/tcp(IPv4)或/proc/net/tcp6(IPv6)中拉取到对应对端信息:- 先用
fstat()获取当前socket fd对应的inode号:struct stat sock_stat; if (fstat(sock_fd, &sock_stat) == 0) { ino_t sock_inode = sock_stat.st_ino; } - 遍历
/proc/net/tcp的所有条目,匹配inode字段对应的行,转换rem_address(十六进制大端IP)和rem_port(十六进制端口)字段即可得到完整的对端地址。
- 先用
- 方案3:临时调试用抓包方案
如果只是临时排查问题,可以直接用tcpdump过滤对应监听端口/目标端口的所有TCP流量,出现ECONNRESET报错时直接从抓包日志中匹配对应五元组即可,不需要修改任何业务代码。
注意:如果已经对socket执行了
close()操作释放了文件描述符,所有方案都无法再获取对应连接的对端信息,获取操作必须在close()调用前执行。
内容的提问来源于stack exchange,提问作者Mark Ransom
相关产品推荐
相关产品推荐

