在linux网络编程中,我们经常会遇到这两个错误。这两个错误出现的情况有些类似,又有些不同。先看下glibc对于这两个错误的描述:
#. TRANS Broken pipe; there is no process reading from the other end of a pipe. #. TRANS Every library function that returns this error code also generates a #. TRANS @code{SIGPIPE} signal; this signal terminates the program if not handled #. TRANS or blocked. Thus, your program will never actually see @code{EPIPE} #. TRANS unless it has handled or blocked @code{SIGPIPE}. #: sysdeps/generic/siglist.h:39 sysdeps/gnu/errlist.c:359 #: sysdeps/unix/siglist.c:39 msgid "Broken pipe" msgstr "断开的管道" #. TRANS A network connection was closed for reasons outside the control of the #. TRANS local host, such as by the remote machine rebooting or an unrecoverable #. TRANS protocol violation. #: sysdeps/gnu/errlist.c:614 msgid "Connection reset by peer" msgstr ""
broken pipe:
broken pipe只出现在调用write的时候。broken pipe的意思是对端的管道已经断开,往往发生在远端把这个读/写管道关闭了,你无法在对这个管道进行读写操作。从tcp的四次挥手来讲,远端已经发送了FIN序号,告诉你我这个管道已经关闭,这时候,如果你继续往管道里写数据,第一次,你会收到一个远端发送的RST信号,如果你继续往管道里write数据,操作系统就会给你发送SIGPIPE的信号,并且将errno置为Broken pipe(32),如果你的程序默认没有对SIGPIPE进行处理,那么程序会中断退出。一般情况下,可以用signal(SIGPIPE,SIG_IGN)忽略这个信号,这样的话程序不会退出,但是write会返回-1并且将errno置为Broken pipe(32)。broken pipe只会出现在往对端已经关闭的管道里写数据的情况下(在收到对端的RST序号后第一次写不会出现broke pipe,而是write返回-1,这时候正确的做法应该是本端也close这个管道,如果继续write,那么就会出现这个错误)。
tcpdump截包情况如下:
connection reset by peer:
connection reset by peer在调用write或者read的时候都会出现。按照glibc的说法,是such as by the remote machine rebooting or an unrecoverable protocol violation。从字面意义上来看,是表示远端机器重启或者发生不可恢复的错误。从我的测试来看,目前只出现在对端直接kill掉进程的情况。这两种情况有什么不同呢?对比tcpdump的截包图来看,直接kill掉远端进程的话,远端并没有发送FIN序号,来告诉对方,我已经关闭管道,而是直接发送了RST序号,而远端如果调用close或者shutdown的话,是会发送FIN序号的。按照TCP的四次挥手来看,是需要FIN这个序号的。个人猜测,如果在本端没有收到对方的FIN序号而直接收到了RST序号的话,表明对端出现了machine rebooting or an unrecoverable protocol violation,这时候对这个管道的IO操作,就会出现connection reset by peer错误。
tcpdump截包情况如下:
补充一下tcp的三次握手和四次挥手的过程图片,帮助理解:
如果有不对的地方,望指正~