主程序先建立一个全局Socket连接句柄后,fork()出一子进程,子进程获得了父进程数据空间、堆和栈的复制品。然后主子进程共同使用该连接句柄。这时此socket的引用计数为2, 任一进程关闭后对引用计数会-1,直到引用计数=0时,socket关闭。在某些情况下主进程需断开该socket并重新连接,此时此socket会无法断开。
通过如下程序测试
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/signal.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/wait.h>
int sock;
void
catch_signal(int sig)
{
if (sig == SIGUSR1)
{
printf("close socket\n");
close(sock);
}
}
int runapp()
{
pid_t pid, pidwait;
int waitcnt;
int status;
if ((pid = fork()) == 0 ) {
printf("This is child process....\n");
int itt = 5;
//close(sock);
execl("/bin/testsock", "testsock", "-a", NULL);
exit(3);
}
printf("pid : %d\n", pid);
waitcnt = 0;
do{
pid1=waitpid(pid, &status, WNOHANG); /* 使用了WNOHANG参数,waitpid不会在这里等待 */
if(pid==0){ /* 如果没有收集到子进程 */
sleep(1);
++waitcnt;
}
}while((pidwait==0) && (waitcnt < 2));
if (pidwait == pid)
{
printf("stustus form pid %d\n", WEXITSTATUS(status));
}
return 0;
}
int main(int argc, char * argv[])
{
signal(SIGUSR1, catch_signal);
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock <= 0)
{
//
// Failed to create the socket
//
printf("failed to create socket\n");
return 0;
}
struct linger ling;
ling.l_onoff = 0;
ling.l_linger = 0;
/* if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (char*) &ling, sizeof (ling)) != 0)
{
}*/
// setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) NULL, 0);
//
/*int on = 1;
if( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)) !=0) {
}*/
//
// Bind to any local address
//
struct sockaddr_in sockAdd;
memset((char*) &sockAdd, 0, sizeof (sockAdd));
sockAdd.sin_family = AF_INET;
inet_aton("10.3.24.100", (in_addr*)&(sockAdd.sin_addr));
sockAdd.sin_port = htons(5999);
int result = bind(sock, (struct sockaddr*)&sockAdd, sizeof(sockAdd));
if (result != 0)
{
close(sock);
sock = -1;
return 0;
}
//
// Retrieve the port
//
/*int localPort = 0;
socklen_t addrLen = sizeof(sockAdd);
if (getsockname(sock, (struct sockaddr*)&sockAdd, &addrLen) == 0)
{
localPort = ntohs(sockAdd.sin_port);
}
else
{
return 0;
}*/
int i = runapp();
printf("i : %d\n", i);
while(1)
{
sleep(10);
}
close (sock);
return true;
}
在函数runapp中如果在fork后没有close掉该socket。我们通过SIGUSR1来让主进程关闭socket
AN# ps -aux | grep testapp
15 3409 0.0 0.0 1244 784 p1 S+ 11:49AM 0:00.08 ./testapp
AN# kill -30 3409
收到SIGUSR1后,主进程会关闭socket,但该socket依然存在
udp4 0 0 10.3.24.100.5999 *.*
在关闭完/bin/testsock进程后, 此socket才会被关闭。
避免这个问题需要在fork完之后在子进程不再用到该socket的话在子进程中先close掉该socket。如果子进程根本就不会用的该socket可以用fcntl(sock,F_SETFD,1)来设置运行exec是关闭该socket句柄;
需要注意的一点,如果是使用system来运行别的程序,也会有这种情况。
通过如下程序测试
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/signal.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/wait.h>
int sock;
void
catch_signal(int sig)
{
if (sig == SIGUSR1)
{
printf("close socket\n");
close(sock);
}
}
int runapp()
{
pid_t pid, pidwait;
int waitcnt;
int status;
if ((pid = fork()) == 0 ) {
printf("This is child process....\n");
int itt = 5;
//close(sock);
execl("/bin/testsock", "testsock", "-a", NULL);
exit(3);
}
printf("pid : %d\n", pid);
waitcnt = 0;
do{
pid1=waitpid(pid, &status, WNOHANG); /* 使用了WNOHANG参数,waitpid不会在这里等待 */
if(pid==0){ /* 如果没有收集到子进程 */
sleep(1);
++waitcnt;
}
}while((pidwait==0) && (waitcnt < 2));
if (pidwait == pid)
{
printf("stustus form pid %d\n", WEXITSTATUS(status));
}
return 0;
}
int main(int argc, char * argv[])
{
signal(SIGUSR1, catch_signal);
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock <= 0)
{
//
// Failed to create the socket
//
printf("failed to create socket\n");
return 0;
}
struct linger ling;
ling.l_onoff = 0;
ling.l_linger = 0;
/* if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (char*) &ling, sizeof (ling)) != 0)
{
}*/
// setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) NULL, 0);
//
/*int on = 1;
if( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on)) !=0) {
}*/
//
// Bind to any local address
//
struct sockaddr_in sockAdd;
memset((char*) &sockAdd, 0, sizeof (sockAdd));
sockAdd.sin_family = AF_INET;
inet_aton("10.3.24.100", (in_addr*)&(sockAdd.sin_addr));
sockAdd.sin_port = htons(5999);
int result = bind(sock, (struct sockaddr*)&sockAdd, sizeof(sockAdd));
if (result != 0)
{
close(sock);
sock = -1;
return 0;
}
//
// Retrieve the port
//
/*int localPort = 0;
socklen_t addrLen = sizeof(sockAdd);
if (getsockname(sock, (struct sockaddr*)&sockAdd, &addrLen) == 0)
{
localPort = ntohs(sockAdd.sin_port);
}
else
{
return 0;
}*/
int i = runapp();
printf("i : %d\n", i);
while(1)
{
sleep(10);
}
close (sock);
return true;
}
在函数runapp中如果在fork后没有close掉该socket。我们通过SIGUSR1来让主进程关闭socket
AN# ps -aux | grep testapp
15 3409 0.0 0.0 1244 784 p1 S+ 11:49AM 0:00.08 ./testapp
AN# kill -30 3409
收到SIGUSR1后,主进程会关闭socket,但该socket依然存在
udp4 0 0 10.3.24.100.5999 *.*
在关闭完/bin/testsock进程后, 此socket才会被关闭。
避免这个问题需要在fork完之后在子进程不再用到该socket的话在子进程中先close掉该socket。如果子进程根本就不会用的该socket可以用fcntl(sock,F_SETFD,1)来设置运行exec是关闭该socket句柄;
需要注意的一点,如果是使用system来运行别的程序,也会有这种情况。
转载于:https://blog.51cto.com/flybear/275710