Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/373.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
javanio:opu-ACCEPT和opu-READ之间的关系?_Java_Sockets_Nio - Fatal编程技术网

javanio:opu-ACCEPT和opu-READ之间的关系?

javanio:opu-ACCEPT和opu-READ之间的关系?,java,sockets,nio,Java,Sockets,Nio,我正在为我的项目重新编写核心NIO服务器网络代码,并试图找出何时应该“存储”连接信息以供将来使用。例如,一旦客户机以常规方式连接,我将存储并关联该连接客户机的SocketChannel对象,以便随时向该客户机写入数据。通常,我使用客户端的IP地址(包括端口)作为映射到SocketChannel对象的HashMap中的键。这样,我可以轻松地查找他们的IP地址,并通过SocketChannel异步向他们发送数据 这可能不是最好的方法,但是它是有效的,而且这个项目太大,不能改变它的基本网络代码,尽管我

我正在为我的项目重新编写核心NIO服务器网络代码,并试图找出何时应该“存储”连接信息以供将来使用。例如,一旦客户机以常规方式连接,我将存储并关联该连接客户机的SocketChannel对象,以便随时向该客户机写入数据。通常,我使用客户端的IP地址(包括端口)作为映射到SocketChannel对象的HashMap中的键。这样,我可以轻松地查找他们的IP地址,并通过SocketChannel异步向他们发送数据

<>这可能不是最好的方法,但是它是有效的,而且这个项目太大,不能改变它的基本网络代码,尽管我会考虑建议。然而,我的主要问题是:

我应该在什么时候“存储”袜子通道以备将来使用?一旦连接被接受(通过OP_ACCEPT),我就一直在存储对SocketChannel的引用。我觉得这是一种有效的方法,因为我可以假设当OP_READ事件进入时map条目已经存在。否则,每次OP_读取时,我都需要对HashMap进行一次计算代价高昂的检查,很明显,对于一个客户机,这些检查的次数要比OP_接受的次数多得多。我想,我担心的是,可能有一些连接被接受(OP_ACCEPT),但从未发送任何数据(OP_READ)。这可能是由于防火墙问题或客户端或网络适配器故障造成的。我认为这可能会导致“僵尸”连接不活跃,但也永远不会收到关闭消息

我重新编写网络代码的部分原因是,在极少数情况下,我的客户端连接进入了一种奇怪的状态。我在想,我处理OP_ACCEPT和OP_READ的方式,包括我用来假设连接“有效”并且可以存储的信息,可能是错误的


很抱歉,我的问题没有更具体,我只是在寻找最好、最有效的方法来确定SocketChannel是否真正有效,以便存储对它的引用。非常感谢您的帮助

> P>如果使用选择器和非阻塞IO,那么您可能需要考虑允许NIO本身跟踪通道和状态数据之间的关联。调用SelectionKey.register()时,可以使用三参数形式传递“附件”。在将来的任何时候,SelectionKey都会返回您提供的附件对象。(这显然是受到操作系统级API中“void*user_data”类型参数的启发。)

该附件保留在密钥中,因此它是保存状态数据的方便位置。很好的一点是,从通道到键再到附件的所有映射都已经由NIO处理了,因此您可以减少簿记。簿记——就像地图查找一样——在IO响应程序循环中确实会造成伤害

作为一项附加功能,您还可以在以后更改附件,因此,如果协议的不同阶段需要不同的状态对象,您也可以在SelectionKey上跟踪它

关于你发现你的连接处于一种奇怪的状态,在使用NIO和选择器时有一些微妙之处可能会让你感到厌烦。例如,一旦SelectionKey发出读取准备就绪的信号,下次其他线程调用select()时,它将继续准备读取。因此,很容易会有多个线程试图读取套接字。另一方面,如果在执行读取操作时尝试取消注册要读取的键,那么最终可能会出现线程错误,因为SelectionKeys及其兴趣操作只能由实际调用select()的线程操作。因此,总的来说,这个API有一些尖锐的优点,要使所有的状态处理正确是很困难的

哦,还有一种可能性,取决于谁先关闭套接字,在您明确询问之前,您可能会注意到或可能不会注意到已关闭的套接字。我记不起头顶上的确切细节,但它是这样的:客户端一半关闭其套接字端,这不会在选择键上发出任何就绪操作的信号,因此socketchannel永远不会被读取。这会在客户机上留下一堆处于等待状态的套接字


作为最后一项建议,如果您正在进行异步IO,那么我肯定会推荐“面向模式的软件体系结构”(POSA)系列中的几本书。第2卷涉及很多IO模式。(例如,NIO非常适合第2卷中的Reactor模式。它解决了我上面提到的一系列状态处理问题。)第4卷包括这些模式,并将它们嵌入到一般分布式系统的大环境中。这两本书都是非常有价值的资源。

另一种选择可能是查看现有的NIO套接字框架,可能的候选者有:


哇,感谢您提供的大量(和高质量)帮助!我正在尽我所能研究这些东西我想你指的是SocketChannel.register(),不是SelectionKey.register(),对吧似乎我可以通过对NIO只使用一个线程来避免一些线程问题,对吗?--定期检查应该关闭的候选者的等待时间状态是否合理?(你提到的半封闭的问题)非常感谢!1) 是,register()位于SelectableChannel(SocketChannel扩展的)上。这就是我的意思。2) 您可以只使用一个线程进行选择,然后将通道切换为读/写操作。如果您处理许多并发连接,您会发现一个线程本身无法跟上。交接很棘手。3) 定期寻找半封闭的插座对我来说很有效。