TCP 正常关闭连接
TCP 连接是双向的。TCP 连接的每一端都有一个输入队列和一个输出队列,用于数据的读或写。放入一端输出队列中的数据最终会出现在另一端的输入队列中。
1、完全关闭与半关闭
应用程序可以关闭 TCP 输入和输出信道中的任意一个,或者将两者都关闭了。套接字调用 close()会将 TCP 连接的输入和输出信道都关闭了。这被称作“完全关闭”。还可以用套接字调用 shutdown()单独关闭输入或输出信道。这被称为“半关闭”。
2、TCP 关闭及重置错误
简单的 HTTP 应用程序可以只使用完全关闭。但当应用程序开始与很多其他类型的 HTTP 客户端、服务器和代理进行对话且开始使用管道化持久连接时,使用半关闭来防止对等实体收到非预期的写入错误就变得很重要了。
总之,关闭连接的输出信道总是很安全的。连接另一端的对等实体会在从其缓冲区中读出所有数据之后收到一条通知,说明流结束了,这样它就知道你将连接关闭了。关闭连接的输入信道比较危险,除非你知道另一端不打算再发送其他数据了。
如果另一端向你已关闭的输入信道发送数据,操作系统就会向另一端的机器回送一条 TCP“连接被对端重置”的报文。大部分操作系统都会将这种情况作为很严重的错误来处理,删除对端还未读取的所有缓存数据。对管道化连接来说,这是非常糟糕的事情。
比如你已经在一条持久连接上发送了 10 条管道式请求了,响应也已经收到了,正在操作系统的缓冲区中存着呢(但应用程序还未将其读走)。现在,假设你发送了第 11 条请求,但服务器认为你使用这条连接的时间已经够长了,决定将其关闭。那么你的第 11 条请求就会被发送到一条已关闭的连接上去,并会向你回送一条重置信息。这个重置信息会清空你的输入缓冲区。
当你最终要去读取数据的时候,会得到一个连接被对端重置的错误,已缓存的未读响应数据都丢失了,尽管其中的大部分都已经成功抵达你的机器了。
3、正常关闭
HTTP 规范建议,当客户端或服务器突然要关闭一条连接时,应该“正常地关闭传输连接”,但它并没有说明应该如何去做。
总之,实现正常关闭的应用程序首先应该关闭它们的输出信道,然后等待连接另一端的对等实体关闭它的输出信道。当两端都告诉对方它们不会再发送任何数据(比如关闭输出信道)之后,连接就会被完全关闭,而不会有重置的危险。但不幸的是,无法确保对等实体会实现半关闭,或对其进行检查。
因此,想要正常关闭连接的应用程序应该先半关闭其输出信道,然后周期性地检查其输入信道的状态(查找数据,或流的末尾)。如果在一定的时间区间内对端没有关闭输入信道,应用程序可以强制关闭连接,以节省资源。
版权声明: 本文为 InfoQ 作者【阿泽🧸】的原创文章。
原文链接:【http://xie.infoq.cn/article/c108a0eff9950a90cf67fb24e】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论