socket通信中EPIPE 错误
来源:互联网 发布:apache ant配置 编辑:程序博客网 时间:2024/06/08 05:46
The send() function shall fail if:
[EPIPE] The socket is shut down for writing, or the socket is connection-mode and is no longer connected. In the latter case, and if the socket is of type SOCK_STREAM or SOCK_SEQPACKET and the MSG_NOSIGNAL flag is not set, the SIGPIPE signal is generated to the calling thread.
You can avoid this by using the MSG_NOSIGNAL
flag on the send()
call, or by ignoring the SIGPIPE
signal with signal(SIGPIPE, SIG_IGN)
at the beginning of your program. Then the send()
function will return -1 and set errno
to EPIPE
in this situation.
A simple way to check would be to do a 0 byte write(2) to the pipe and check the return. If you're catching SIGPIPE or checking for EPIPE, you get the error. But that's just the same as if you go ahead and do your real write, checking for the error return. So, just do the write and handle an error either in a signal handler (SIGPIPE) or, if the signal is ignored, by checking the error return from write.
转载自:http://hi.baidu.com/tangzhenjiang/blog/item/9700f8ed7475434879f05570.html
page1:
假设Server A上面有Process X,它有一个socket M,和另外的Server B上面的Process Y的 Socket N以TCP协议连接上了,那么,据我所知,有2种情况会出现RST包:
(1)X没有close socket就退出了,然后Y继续向M send数据,A的内核就会发送RST 到 socket N;
(2)X设置了SO_LINGER,其中l_onoff 非0, l_linger 为0,这样当A close socket M的时候,也会发送RST到socket N。
当socket N收到了RST,select的结果为socket可读,则:
(a)如果这个时候调用recv,返回-1,errno为ECONNRESET,如果再次调用recv,返回-1,errno为EPIPE,同样产生EPIPE信号;
(b)如果这个时候调用send,返回-1,errno为EPIPE,同时会产生SIGPIPE信号。
转载自:http://blogold.chinaunix.net/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 to readline may happen before the server's RST is received by the client, or it may happen after. If the readline happens before the RST is received, as we've shown in our example, the result is an unexpected EOF in the client. But if the RST arrives first, the result is an ECONNRESET ("Connection reset by peer") error return from readline.
以上解释了测试3的现象,write时,收到RST.
What happens if the client ignores the error return from readline and writes more data to the server? This can happen, for example, if the client needs to perform two writes to the server before reading anything back, with the first write eliciting the RST.
The rule that applies is: When a process writes to a socket that has received an RST, the SIGPIPE signal is sent to the process. The default action of this signal is to terminate the process , so the process must catch the signal to avoid being involuntarily terminated.
If the process either catches the signal and returns from the signal handler, or ignores the signal, the write operation returns EPIPE.
以上解释了测试1,2的现象,write一个已经接受到RST的socket,系统内核会发送SIGPIPE给发送进程,如果进程catch/ignore这个信号,write都返回EPIPE错误.
因此,UNP建议应用根据需要处理SIGPIPE信号,至少不要用系统缺省的处理方式处理这个信号,系统缺省的处理方式是退出进程,这样你的应用就很难查处处理进程为什么退出。
- socket通信中EPIPE 错误
- socket通信中EPIPE 错误
- socket write出EPIPE错误
- Socket Intro - SIGPIPE and EPIPE
- android系统中ALSA架构audio -EPIPE错误分析及对策
- Android Socket通信 错误笔记
- Java 中 Socket 通信
- Android中Socket通信
- java中socket通信
- Java中Socket通信
- PHP中socket通信
- .NET 中Socket通信示例
- Java中Socket网络通信
- 网络中进程通信-----socket
- java中Socket相互通信
- 关于socket通信中在connect()遇到的Operation now in progress错误
- Socket异步通信中的EAGAIN错误
- socket中10044错误原因
- 实现收藏本网站的功能
- 出错的程序
- 聊聊可空类型
- Eclipse相关文章
- Java中Date各种相关用法
- socket通信中EPIPE 错误
- Sublime Text 2安装插件管理器的方法
- 黑马程序员_java开发的前奏2
- 第十周自由练习项目——函数调用求最小值
- VTK与ITK的详细安装指南
- tinxml解析CDATA字段
- 一天面试助理的亲身经历,其中涉及到几个程序员都关心的话题,希望能对大家有所帮助。
- tinyxml解析CDATA
- Android service onstartcomand 返回值