SIGPIPE导致的程序退出
来源:互联网 发布:gsm r直放站网络优化 编辑:程序博客网 时间:2024/05/09 17:04
当服务器close一个连接时,若client端接着发数据。根据TCP协议的规定,会收到一个RST响应,client再往这个服务器发送数据时,系统会发出一个SIGPIPE信号给进程,告诉进程这个连接已经断开了,不要再写了。
根据信号的默认处理规则SIGPIPE信号的默认执行动作是terminate(终止、退出),所以client会退出。若不想客户端退出可以把SIGPIPE设为SIG_IGN
如: signal(SIGPIPE,SIG_IGN);
这时SIGPIPE交给了系统处理。
服务器采用了fork的话,要收集垃圾进程,防止僵尸进程的产生,可以这样处理:
signal(SIGCHLD,SIG_IGN); 交给系统init去回收。
这里子进程就不会产生僵尸进程了
以下链接至:
http://www.cublog.cn/u/31357/showart_242605.html
#include "unp.h"
#define MAXBUF 40960
void processSignal(int signo)
{
printf("Signal is %d/n", signo);
signal(signo, processSignal);
}
void
str_cli(FILE *fp, int sockfd)
{
char sendline[MAXBUF], recvline[MAXBUF];
while (1) {
memset(sendline, 'a', sizeof(sendline));
printf("Begin send %d data/n", MAXBUF);
Writen(sockfd, sendline, sizeof(sendline));
sleep(5);
}
}
int
main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
signal(SIGPIPE, SIG_IGN);
//signal(SIGPIPE, processSignal);
if (argc != 2)
err_quit("usage: tcpcli [port]");
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(atoi(argv[1]));
Inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));
str_cli(stdin, sockfd); /* do it all */
exit(0);
}
为了方便观察错误输出,lib/writen.c也做了修改,加了些日志:
/* include writen */
#include "unp.h"
ssize_t /* Write "n" bytes to a descriptor. */
writen(int fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr = vptr;
nleft = n;
while (nleft > 0) {
printf("Begin Writen %d/n", nleft);
if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
if (nwritten < 0 && errno == EINTR) {
printf("intterupt/n");
nwritten = 0; /* and call write() again */
}
else
return(-1); /* error */
}
nleft -= nwritten;
ptr += nwritten;
printf("Already write %d, left %d, errno=%d/n", nwritten, nleft, errno);
}
return(n);
}
/* end writen */
void
Writen(int fd, void *ptr, size_t nbytes)
{
if (writen(fd, ptr, nbytes) != nbytes)
err_sys("writen error");
}
client.c放在tcpclieserv目录下,修改了Makefile,增加了client.c的编译目标
client: client.c
${CC} ${CFLAGS} -o $@ $< ${LIBS}
接着就可以开始测试了。
测试1 忽略SIGPIPE信号,writen之前,对方关闭接受进程
本机服务端:
Begin Writen 40960
Already write 40960, left 0, errno=0
Begin send 40960 data
Begin Writen 40960
Already write 40960, left 0, errno=0
执行到上步停止服务端,client会继续显示:
Begin Writen 40960
writen error: Broken pipe(32)
结论:可见write之前,对方socket中断,发送端write会返回-1,errno号为EPIPE(32)
测试2 catch SIGPIPE信号,writen之前,对方关闭接受进程
修改客户端代码,catch sigpipe信号
//signal(SIGPIPE, SIG_IGN);
signal(SIGPIPE, processSignal);
本机服务端:
Begin Writen 40960
Already write 40960, left 0, errno=0
Begin send 40960 data
Begin Writen 40960
Already write 40960, left 0, errno=0
执行到上步停止服务端,client会继续显示:
Begin Writen 40960
Signal is 13
writen error: Broken pipe(32)
结论:可见write之前,对方socket中断,发送端write时,会先调用SIGPIPE响应函数,然后write返回-1,errno号为EPIPE(32)
测试3 writen过程中,对方关闭接受进程
为了方便操作,加大1次write的数据量,修改MAXBUF为4096000
本机服务端:
Begin Writen 4096000
执行到上步停止服务端,client会继续显示:
Begin Writen 3506179
writen error: Connection reset by peer(104)
结论:可见socket write中,对方socket中断,发送端write会先返回已经发送的字节数,再次write时返回-1,errno号为ECONNRESET(104)
为什么以上测试,都是对方已经中断socket后,发送端再次write,结果会有所不同呢。从后来找到的UNP5.12,5.13能找到答案
The client's call toreadline may happen before the server's RST is received by the client,or it may happen after. If the readline happens before the RST isreceived, as we've shown in our example, the result is an unexpectedEOF in the client. But if the RST arrives first, the result is anECONNRESET ("Connection reset by peer") error return from readline.
以上解释了测试3的现象,write时,收到RST.
What happens if the clientignores the error return from readline and writes more data to theserver? This can happen, for example, if the client needs to performtwo writes to the server before reading anything back, with the firstwrite eliciting the RST.
The rule that applies is:When a process writes to a socket that has received an RST, the SIGPIPEsignal is sent to the process. The default action of this signal is toterminate the process, so the process must catch the signal to avoidbeing involuntarily terminated.
If the process eithercatches the signal and returns from the signal handler, or ignores thesignal, the write operation returns EPIPE.
以上解释了测试1,2的现象,write一个已经接受到RST的socket,系统内核会发送SIGPIPE给发送进程,如果进程catch/ignore这个信号,write都返回EPIPE错误.
因此,UNP建议应用根据需要处理SIGPIPE信号,至少不要用系统缺省的处理方式处理这个信号,系统缺省的处理方式是退出进程,这样你的应用就很难查处处理进程为什么退出。
- SIGPIPE导致的程序退出
- SIGPIPE导致的程序退出
- SIGPIPE导致的程序退出
- SIGPIPE导致程序退出
- 关于SIGPIPE导致的程序退出
- 关于SIGPIPE导致的程序退出
- 转载: 关于SIGPIPE导致的程序退出
- 关于SIGPIPE导致的程序退出
- 关于SIGPIPE导致的程序退出
- 关于SIGPIPE导致的程序退出
- 转载: 关于SIGPIPE导致的程序退出
- 关于SIGPIPE导致的程序退出
- 关于SIGPIPE导致的程序退出
- 关于SIGPIPE导致的程序退出
- 关于SIGPIPE导致的程序退出
- 关于SIGPIPE导致的程序退出
- 关于SIGPIPE导致的程序退出
- 关于SIGPIPE导致的程序退出
- 话说程序员的职业生涯
- Top 10 Hacks of 2009 and WAF Mitigations
- 查看设置JVM内存信息
- poj 1221 UNIMODAL PALINDROMIC DECOMPOSITIONS 动态规划
- linux send recv函数详解
- SIGPIPE导致的程序退出
- live writer test
- 解决linux vim乱码问题
- awk用法小结
- .net面试题集1
- 内存错误:allocation failed: out of vmalloc space - use vmalloc= to increase size.
- fedora 利用axel实现yum多线程下载
- pku 1421 poj 1421 Peter's calculator
- 利用iconv函数族进行编码转换