Socket编程实践(8) --TCP服务器常见问题(3)
来源:程序员人生 发布时间:2014-12-19 08:38:08 阅读次数:2344次
服务端多进程避免僵尸进程的方法
1)通过疏忽SIGCHLD信号,解决僵尸进程
在server端代码中添加
signal(SIGCHLD, SIG_IGN);
2)通过wait/waitpid方法,解决僵尸进程
signal(SIGCHLD,onSignalCatch);
void onSignalCatch(int signalNumber)
{
wait(NULL);
}
Server端部份代码:
//return a socket that have start listened.
int mkATCPServer(int serverPort, int backlog = SOMAXCONN)
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if (sockfd == ⑴)
{
err_exit("socket error");
}
//add address reused
int on = 1;
if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) == ⑴)
{
err_exit("setsockopt SO_REUSEADDR error");
}
//band a local address and port
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(serverPort);
serverAddr.sin_addr.s_addr = INADDR_ANY; //band an any IP address
if (bind(sockfd,(struct sockaddr *)&serverAddr,sizeof(serverAddr)) == ⑴)
{
err_exit("bind error");
}
//start to listen.
if (listen(sockfd,backlog) == ⑴)
{
err_exit("listen error");
}
return sockfd;
}
void onSignalCatch(int signalNumber)
{
waitpid(⑴,NULL,WNOHANG);
}
int main()
{
//安装SIGCHLD信号处理函数
signal(SIGCHLD,onSignalCatch);
int serverSockfd = mkATCPServer(8002);
struct sockaddr_in peerAddr;
socklen_t peerLen = sizeof(peerAddr);
while (true)
{
//接受链接
int peerSockfd = accept(serverSockfd, (struct sockaddr *)&peerAddr,&peerLen);
if (peerSockfd == ⑴)
{
err_exit("accept error");
}
.....
//其他部份代码与前面类似
多客户端同时关闭问题
问题描写以下:
客户端代码实现代码
//其他代码如前
//....
int main()
{
int serverSocket[10];
int socketCount = 10;
for (int i = 0; i < socketCount; ++i)
{
serverSocket[i] = mkATCPClient(8002,"127.0.0.1");
}
sleep(100);
return 0;
}
在客户运行进程中按下Ctrl+C,则可以看到在server端启动10个子进程,并且所有的客户端全部1起断开的情况下,产生的僵尸进程数是惊人的(此时也证明了SIGCHLD信号是不可靠的)!
解决方法:
//server端部份代码以下:
//其他如前....
void onSignalCatch(int signalNumber)
{
int ret = 0;
//注意此处!!!!
while ((ret = waitpid(⑴,NULL,WNOHANG) != ⑴))
;
}
int main()
{
signal(SIGCHLD,onSignalCatch);
int serverSockfd = mkATCPServer(8002);
...
从下图可以看出,出了监听server进程,已没有僵尸进程了!
生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠