- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
作为 recent question 的后续行动,我想知道为什么在 Java 中,如果不尝试在 TCP 套接字上读/写,就不可能检测到套接字已被对等方优雅地关闭?无论是使用 pre-NIO Socket
还是 NIO SocketChannel
,似乎都是这种情况。
当对等端优雅地关闭 TCP 连接时,连接两端的 TCP 堆栈都知道这一事实。服务器端(启动关闭的那个)最终处于状态 FIN_WAIT2
,而客户端(没有明确响应关闭的那个)最终处于状态 CLOSE_WAIT
。为什么 Socket
或 SocketChannel
中没有可以查询 TCP 堆栈以查看底层 TCP 连接是否已终止的方法?是不是 TCP 栈没有提供这样的状态信息?还是避免对内核进行昂贵的调用是一项设计决策?
在已经发布了这个问题的一些答案的用户的帮助下,我想我知道问题可能来自哪里。没有明确关闭连接的一方最终处于 TCP 状态 CLOSE_WAIT
意味着连接正在关闭并等待一方发出自己的 CLOSE
操作。我想 isConnected
返回 true
和 isClosed
返回 false
是公平的,但为什么没有类似的东西isClosing
?
以下是使用 pre-NIO 套接字的测试类。但是使用 NIO 可以获得相同的结果。
import java.net.ServerSocket;
import java.net.Socket;
public class MyServer {
public static void main(String[] args) throws Exception {
final ServerSocket ss = new ServerSocket(12345);
final Socket cs = ss.accept();
System.out.println("Accepted connection");
Thread.sleep(5000);
cs.close();
System.out.println("Closed connection");
ss.close();
Thread.sleep(100000);
}
}
import java.net.Socket;
public class MyClient {
public static void main(String[] args) throws Exception {
final Socket s = new Socket("localhost", 12345);
for (int i = 0; i < 10; i++) {
System.out.println("connected: " + s.isConnected() +
", closed: " + s.isClosed());
Thread.sleep(1000);
}
Thread.sleep(100000);
}
}
当测试客户端连接到测试服务器时,即使服务器开始关闭连接,输出仍然保持不变:
connected: true, closed: false
connected: true, closed: false
...
最佳答案
我经常使用套接字,主要是与选择器一起使用,虽然不是网络 OSI 专家,但据我了解,调用 shutdownOutput()
on a Socket 实际上在网络(FIN)上发送一些东西,唤醒我在另一端的选择器(在 C 语言中的行为相同)。这里你有检测:实际检测到一个读操作,当你尝试它时会失败。
在您提供的代码中,关闭套接字将关闭输入和输出流,无法读取可能可用的数据,因此会丢失它们。 Java Socket.close()
方法执行“优雅”断开连接(与我最初的想法相反),因为留在输出流中的数据将被发送随后是 FIN 以表示其关闭。 FIN 将被对方确认,就像任何常规数据包都会1。
如果你需要等待对方关闭它的socket,你需要等待它的FIN。为了实现这一点,您必须检测 Socket.getInputStream().read() < 0
,这意味着你应该不关闭你的套接字,因为它会关闭它的InputStream
。
从我在 C 中所做的,现在在 Java 中,实现这样的同步关闭应该这样完成:
read()
并检测远程close()
InputStream
直到我们收到来自另一端的回复 FIN(因为它会检测到 FIN,它会经历同样的优雅断开过程)。这在某些操作系统上很重要,因为只要其中一个缓冲区仍然包含数据,它们实际上就不会关闭套接字。它们被称为“幽灵”套接字,并在操作系统中耗尽了描述符编号(现代操作系统可能不再是问题)Socket.close()
或关闭其 InputStream
或 OutputStream
)如以下 Java 代码片段所示:
public void synchronizedClose(Socket sok) {
InputStream is = sok.getInputStream();
sok.shutdownOutput(); // Sends the 'FIN' on the network
while (is.read() > 0) ; // "read()" returns '-1' when the 'FIN' is reached
sok.close(); // or is.close(); Now we can close the Socket
}
当然双方必须使用相同的关闭方式,否则发送部分可能总是发送足够的数据来保持while
循环繁忙(例如,如果发送部分仅发送数据而从不读取以检测连接终止。这很笨拙,但您可能无法控制)。
正如@WarrenDew 在他的评论中指出的那样,丢弃程序(应用层)中的数据会导致应用层的非正常断开连接:尽管所有数据都是在 TCP 层(while
循环)接收的,但它们是丢弃。
1:来自“Fundamental Networking in Java”:见图。 3.3 p.45,以及整个 §3.7,第 43-48 页
关于java - 为什么不尝试 I/O 就不可能检测到 TCP 套接字已被对等方优雅地关闭?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/155243/
我使用下拉菜单提供一些不同的链接,但我希望这些链接在同一选项卡中打开,而不是在新选项卡中打开。这是我找到的代码,但我对 Javascript 非常缺乏知识 var urlmenu = docume
我对 javascript 不太了解。但我需要一个垂直菜单上的下拉菜单,它是纯 JavaScript,所以我从 W3 复制/粘贴脚本:https://www.w3schools.com/howto/t
我已经坐了 4 个小时,试图让我的导航显示下 zipper 接垂直,但它继续水平显示它们。我无法弄清楚为什么会发生这种情况或如何解决它。 如果有人能告诉我我做错了什么,我将不胜感激。我有一个潜移默化的
我正在尝试创建选项卡式 Accordion 样式下拉菜单。我使用 jQuery 有一段时间了,但无法使事件状态达到 100%。 我很确定这是我搞砸的 JS。 $('.service-button').
对于那些从未访问过 Dropbox 的人,这里是链接 https://www.dropbox.com/ 查看“登录”的下拉菜单链接。我如何创建这样的下 zipper 接? 最佳答案 这是 fiddle
我正在制作一个 Liferay 主题,但我在尝试设计导航菜单的样式时遇到了很多麻烦。我已经为那些没有像这样下拉的人改变了导航链接上的经典主题悬停功能: .aui #navigation .nav li
如果您将鼠标悬停在 li 上,则会出现一个下拉菜单。如果您将指针向下移至悬停时出现的 ul,我希望链接仍然带有下划线,直到您将箭头从 ul 或链接移开。这样你就知道当菜单下拉时你悬停在哪个菜单上。 知
我有一个带有多个下拉菜单的导航栏。因此,当我单击第一个链接时,它会打开下拉菜单,但是当我单击第二个链接时,第一个下拉菜单不会关闭。 (所以如果用户点击第二个链接我想关闭下拉菜单) // main.js
我正在尝试制作一个导航下拉菜单(使用 Bootstrap 3),其中链接文本在同一行上有多个不同的对齐方式。 在下面的代码中,下拉列表 A 中的链接在 HTML 中有空格字符来对齐它们,但是空白被忽略
我希望有人能帮我解决这个 Bootstrap 问题,因为我很困惑。 有人要求我在底部垂直对齐图像和其中包含图像的链接。 我面临的问题是他们还希望链接在链接/图像组合上具有 pull-right,这会杀
我正在构建一个 Rails 应用程序,并希望指向我的类的每个实例的“显示”页面的链接显示在“索引”页面的下拉列表中。我目前正在使用带有 options_from_collection_for_sele
我有以下 Bootstrap3 导航菜单 ( fiddle here )。我想设置“突出显示”项及其子链接与下拉列表 1 和 2 链接不同的链接文本(和悬停)的样式。我还希望能够以不同于 Highli
我对导航栏中的下拉菜单有疑问。对于普通的导航链接(无下拉菜单),我将菜单文本放在 H3 中,但是当我尝试对下 zipper 接执行相同操作时,箭头不在标题旁边,而是在标题下方。我决定用 span 替换
我是一名优秀的程序员,十分优秀!