Rob*_*nes 13 language-agnostic sockets network-programming network-protocols
当您读取一个已关闭的TCP套接字时,您会收到一个常规错误,即它返回0表示EOF或-1,以及一个errno可以打印的错误代码perror.
但是,当您编写一个封闭的TCP套接字时,操作系统会发送SIGPIPE到您的应用程序,如果没有捕获,它将终止应用程序
为什么写封闭的TCP套接字比读取它更糟糕?
Rob*_*nes 12
+1给Greg Hewgill以正确的方向引导我的思考过程以找到答案.
SIGPIPE套接字和管道的真正原因是过滤器习语/模式,它适用于Unix系统中的典型I/O.
从管道开始.像grep这样的过滤程序通常写入STDOUT和读取STDIN,可以由shell重定向到管道.例如:
cat someVeryBigFile | grep foo | doSomeThingErrorProne
Run Code Online (Sandbox Code Playgroud)
shell分叉然后exec的这些程序可能会使用dup2系统调用来重定向STDIN,STDOUT并STDERR使用相应的管道.
由于过滤程序grep不知道并且无法知道它的输出已被重定向,因此如果doSomeThingErrorProne崩溃是一个信号,则告诉它停止写入损坏的管道的唯一方法,因为写入的返回值STDOUT很少,如果有的话检查.
带套接字的模拟inetd服务器将取代shell.
作为一个例子,我假设你可以grep变成一个通过TCP套接字操作的网络服务.例如,inetd如果要grep在TCP端口8000 上安装服务器,请将其添加到/etc/services:
grep 8000/tcp # grep server
Run Code Online (Sandbox Code Playgroud)
然后将其添加到/etc/inetd.conf:
grep stream tcp nowait root /usr/bin/grep grep foo
Run Code Online (Sandbox Code Playgroud)
发送SIGHUP到inetd和通过telnet连接到端口8000.这应当引起inetd对叉,DUP插座上STDIN,STDOUT和STDERR然后exec的grep以foo作为参数.如果你开始在telnet中输入grep行将回显那些包含foo的行.
现在将telnet替换为一个名为的程序ticker,例如将实时股票报价流写入STDOUT并获取命令STDIN.有人telnet到端口8000并输入"start java"来获取Sun Microsystems的报价.然后他们起床去吃午饭.telnet莫名其妙地崩溃了.如果没有SIGPIPE发送,那么ticker将继续永远发送报价,从不知道另一端的进程已经崩溃,并且不必要地浪费系统资源.
Gre*_*ill 10
通常,如果你正在写一个套接字,你会期望另一端正在收听.这有点像电话 - 如果你说话,你不会指望对方只是挂断电话.
如果你正在从套接字读取,那么你期望另一端要么(a)发送一些东西,要么(b)关闭套接字.如果您刚刚向另一端发送了类似QUIT命令的内容,则会发生情况(b).
小智 7
将套接字视为发送和接收过程之间的大数据管道.现在假设管道有一个关闭的阀门(插座连接关闭).
如果你正在从插座中读取(试图从管道中取出某些东西),那么尝试阅读那些不存在的东西是没有害处的; 你不会得到任何数据.事实上,正如你所说,你可以得到一个正确的EOF,因为没有更多的数据可供阅读.
但是,写这个封闭的连接是另一回事.数据无法通过,您可能最终放弃了一些重要的通信.(你不能用一个关闭的阀门将水送到管道;如果你尝试,某些东西可能会在某处爆裂,或者至少,背压会在整个地方喷水.)这就是为什么有一个更强大的工具提醒您这种情况,即SIGPIPE信号.
您可以随时忽略或阻止信号,但这样做需要您自担风险.