诡异的TCP链接问题

最近帮同事解决了一个诡异的TCP链接问题,最终找到的缘由是程序在fork时的一个bug。socket

 

现象是这样的:两个进程A和B经过TCP创建Socket链接,运行不定长时间后A发现B断开了,但B进程一直都在,历来没有退出过,并且TCP链接仍然是ESTABLISHED状态。tcp

A进程里的log:ide

2012-01-07T20:18:51.502162Z [warn] multiaccept.cpp:371: Component B is GONEthis

查看B进程(PID为17076)的TCP连接:spa

[root@ucs106-3 ha-cm1]# netstat -anpt|grep 17076进程

tcp 0 0 70.0.0.15:34702 70.0.0.15:7400 ESTABLISHED 17076/Bip

 

再进一步查看,发现更加诡异的事情是,B进程的Socket居然链接到了另一个C进程,C是A fork出来的其中一个子进程。同时ouput buffer阻塞了大量数据。查了半天配置也没有发现是配置文件的错误。get

[root@ucs106-3 ha-cm1]# netstat -anpt|grep 34702it

tcp 0 0 70.0.0.15:34702 70.0.0.15:7400 ESTABLISHED 17076/Bclass

tcp 99884 0 70.0.0.15:7400 70.0.0.15:34702 ESTABLISHED 17089/C

 

最后问题是出在了下面的代码中。

void _on_accept(...)

{

fd = accept(m->fd, (struct sockaddr*)&sa, (socklen_t*)&sa_size);

flags = fcntl(fd, F_GETFL, 0);

flags |= O_NONBLOCK;

fcntl(fd, F_SETFL, flags);

...

//fork C later

}

 

缘由就在于fd是在fork新的子进程以前就创建起来的,由于没有设FD_CLOEXEC标志位,子进程会引用同一个sock descriptor。所以即便父进程A已经断开了与B的链接,子进程C和B之间还会维护一个“假”的链接。

这个从/proc文件系统中也能看到,假设A的PID是7177,C是7232。结果是这样的:

[root@xcp-core-base3 fd]# pwd

/proc/7177/fd

[root@xcp-core-base3 fd]# ls -l|grep socket

lrwx------ 1 root root 64 Jan 16 01:08 10 -> socket:[47153468]

lrwx------ 1 root root 64 Jan 16 01:08 13 -> socket:[47153473]

lrwx------ 1 root root 64 Jan 16 01:08 14 -> socket:[47153481]

lrwx------ 1 root root 64 Jan 16 01:08 15 -> socket:[47153488]

...

[root@xcp-core-base3 fd]# cd /proc/7232/fd

[root@xcp-core-base3 fd]# pwd

/proc/7232/fd

[root@xcp-core-base3 fd]# ls -l|grep socket

lrwx------ 1 root root 64 Jan 16 01:08 13 -> socket:[47153473]

lrwx------ 1 root root 64 Jan 16 01:08 14 -> socket:[47153481]

lrwx------ 1 root root 64 Jan 16 01:08 15 -> socket:[47153488]

...

找到了缘由,解决问题只须要下面一行代码:

  
  
  
  
  1. // Set the FD_CLOEXEC bit so exec'd processes don't get this  
  2. // socket handle automatically.  
  3. fcntl(fd, F_SETFD, FD_CLOEXEC); 
相关文章
相关标签/搜索