2009-07-28 95 views
4

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

这可能不是最好的方法,但它可以工作,并且该项目太大而无法更改其基本网络代码,但我会考虑建议。然而,我的主要问题是:

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

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

对不起,我的问题不是更具体,我只是寻找最好的,最有效的方式来确定一个SocketChannel是否真正有效,所以我可以存储对它的引用。非常感谢您的帮助!

回答

4

如果您使用选择器和非阻塞IO,那么您可能需要考虑让NIO自己跟踪通道与其有状态数据之间的关联。当您调用SelectionKey.register()时,可以使用三参数形式传入“附件”。在将来的每一点上,SelectionKey将始终返回您提供的附件对象。 (这很明显受OS级API中“void * user_data”参数类型的启发。)

该附件保留在键上,所以它是保存状态数据的便利场所。好的是,所有从频道到密钥到附件的映射都将由NIO处理,因此您可以减少记帐工作。簿记 - 像地图查找 - 可以真正伤害IO响应者循环。

作为一个附加功能,您也可以稍后更改附件,因此如果您需要针对协议的不同阶段使用不同的状态对象,则您也可以在SelectionKey上跟踪该状态对象。

关于奇怪的状态,你发现你的连接,有一些微妙的使用NIO和选择器,可能会咬你。例如,SelectionKey一旦发出准备好读取的信号,下次其他线程调用select()时它将继续准备好读取。因此,试图读取套接字的多线程很容易。另一方面,如果您在读取时试图取消注册键的读取,那么最终可能会出现线程错误,因为SelectionKeys和它们的兴趣操作符只能由只有被实际调用的线程操作select( )。所以,总的来说,这个API有一些尖锐的边缘,并且让所有的状态处理正确是很棘手的。

哦,还有一种可能性,取决于谁先关闭套接字,在明确要求之前,您可能注意或不会注意到一个关闭的套接字。我无法回想起头顶的确切细节,但它是这样的:客户端半关闭了它的插槽末端,这是而不是指示选择键上的任何就绪操作,所以socket通道从不阅读。这可以在客户端上留下一堆处于TIME_WAIT状态的套接字。

作为最终的建议,如果你在做异步IO,那么我肯定会推荐几本“面向模式的软件体系结构”(POSA)系列的书籍。第2卷涉及很多IO模式。 (例如,NIO非常适合第2卷中的Reactor模式。它解决了上面提到的那些状态处理问题。)第4卷包含了这些模式,并将它们嵌入到分布式系统的更大范围内。这两本书都是非常宝贵的资源。

+0

哇,感谢大量(和质量)的帮助!我正在研究这个东西,尽我所能。 - 我想你的意思是SocketChannel.register(),而不是SelectionKey.register(),对不对? - 我似乎可以通过仅为我的NIO使用一个线程来避免一些线程问题,对吧? - 定期检查应关闭的候选人的TIME_WAIT状态套接字是否合理? (你提到的半封闭问题) 非常感谢! – DivideByHero 2009-07-28 15:00:24

+0

1)是的,register()在SelectableChannel上(SocketChannel扩展)。这就是我的意思。 2)您只能使用一个线程进行选择,然后关闭通道以进行读取/写入操作。如果你正在处理很多并发连接,你会发现一个线程本身跟不上。这是棘手的交接。 3)定期寻找半封闭的套接字已为我工作。 – mtnygard 2009-07-28 20:38:17