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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/meteor/3.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
使用java选择器唯一标识客户端_Java_Sockets_Nio - Fatal编程技术网

使用java选择器唯一标识客户端

使用java选择器唯一标识客户端,java,sockets,nio,Java,Sockets,Nio,我正在使用java.nio编写一个套接字服务器。因为我需要我的服务器使用0个线程,所以我使用的是java.nio.channels.Selector。我的代码如下所示 while (iterator.hasNext()) { SelectionKey key = (SelectionKey) iterator.next(); iterator.remove(); if (!key.isValid()) { continue; } if (key.

我正在使用java.nio编写一个套接字服务器。因为我需要我的服务器使用0个线程,所以我使用的是
java.nio.channels.Selector
。我的代码如下所示

while (iterator.hasNext()) {
   SelectionKey key = (SelectionKey) iterator.next();

   iterator.remove();

   if (!key.isValid()) {
       continue;
   }

   if (key.isAcceptable()) { // Accept client connections
       this.acceptClient(key);
   } else if (key.isReadable()) { // Read from client
       this.read(key);
   } else if (key.isWritable()) {
       this.write(key);
   }
}

    private void acceptClient(SelectionKey key) throws IOException {
        ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
        SocketChannel channel = serverChannel.accept();
        channel.configureBlocking(false);
        SocketAddress clientAddress= channel.getRemoteAddress();

        //clients is a Hashmap
        clients.put(clientAddress, new Client());
        clientConnected(clientAddress.toString());
        System.out.println("Connected to: " + clientAddress);

        channel.register(this.selector, SelectionKey.OP_READ);
    }
正如您所看到的,我正在为每个接受的客户机创建一个新的客户机对象。我需要做的是,相关的客户端对象处理自己的读写。
我的方法是用地址唯一地标识客户机,并将其转发给相关的客户机对象。

我认为使用客户地址来唯一标识客户不是一个好方法。处理此问题的最佳方法是什么?

使用
选择器注册
频道时:

channel.register(this.selector, SelectionKey.OP_READ);
它将返回一个
SelectionKey
,您可以在以后从
选择器中选择时使用该键

使用该键填充
IdentityHashMap
,以便可以将IO定向到正确的
客户端
实例。正如EJP在回答中指出的,如果没有正确清理,这将泄漏选择键。如果您不想清理这些内容,那么也可以使用
WeakHashMap
,但这样您就依赖于选择器的隐式行为而不是显式行为


EJP建议使用附件可能是最好的选择。虽然我可以想象一个更复杂的场景,您可能需要维护额外的附件,并且可能需要将附件重构为封装,但成本很高。

当您使用
选择器注册
频道时:

channel.register(this.selector, SelectionKey.OP_READ);
它将返回一个
SelectionKey
,您可以在以后从
选择器中选择时使用该键

使用该键填充
IdentityHashMap
,以便可以将IO定向到正确的
客户端
实例。正如EJP在回答中指出的,如果没有正确清理,这将泄漏选择键。如果您不想清理这些内容,那么也可以使用
WeakHashMap
,但这样您就依赖于选择器的隐式行为而不是显式行为

EJP建议使用附件可能是最好的选择。虽然我可以想象一个更复杂的场景,在这个场景中,您可能需要维护额外的附件,并且可能将附件重构为封装,但成本很高

我认为使用客户地址来唯一标识客户不是一个好方法

没什么问题。TCP/IP的语义保证每个接受的套接字都有不同的远程
SocketAddress

但是你不需要它,也不需要地图。只需将
客户端
保存为
选择键
的附件即可。这样,当您关闭
频道时,
客户端
将随着
选择键
自动消失

相反,如其他地方所建议的,更改为
IdentityHashMap
会让您有机会泄漏
SelectionKey
,从而泄漏其
频道
客户端

我认为使用客户地址来唯一标识客户不是一个好方法

没什么问题。TCP/IP的语义保证每个接受的套接字都有不同的远程
SocketAddress

但是你不需要它,也不需要地图。只需将
客户端
保存为
选择键
的附件即可。这样,当您关闭
频道时,
客户端
将随着
选择键
自动消失


相比之下,按照其他地方的建议更改为
IdentityHashMap
会让您有机会泄漏
SelectionKey
,因此它的
频道和
客户端也会泄漏。

为什么要使用
IdentityHashMap
,键的hashCode方法没有很好地定义,而且定义的状态似乎可能与其他键重叠,因此我不相信hashcodes对于每个SelectionKey都是唯一的(即使src表示hashCode()的默认实现,它依赖于地址),这在Javadoc中定义得很好,即
都等于()
hashCode()
是从
对象继承的。我不理解“定义的状态似乎可能与其他键重叠”。它们(当前)是从对象继承的,并且对象对equals和hashcode必须遵守的内容有严格的要求。然而,关于对象的实现细节仍然模糊不清。通常,hashcode和equals会根据对象的内部状态进行更改;SelectionKey指定内部状态,包括准备就绪的内容,该状态在SelectionKey上随时间而变化。由于SelectionKey类没有明确声明hashcode和equals结果不会随时间而改变,因此我认为依赖对象的模糊实现是不安全的。定义良好的是,选择器将返回对同一SelectionKey实例的引用,因此,使用IdenityHashMap与显式定义的行为(忽略隐式定义的行为)非常吻合。为什么要使用
IdentityHashMap
,键的hashCode方法没有很好地定义,而且定义的状态似乎可能与其他键重叠,因此我不相信hashcodes对于每个SelectionKey都是唯一的(即使src表示hashCode()的默认实现,它依赖于地址),这在Javadoc中定义得很好,即
都等于()
hashCode()
是从
对象继承的。我不理解“定义的状态似乎可能与其他键重叠”。它们(当前)是从对象继承的,并且对象对equals和hashcode必须遵守的内容有严格的要求。然而,关于对象的实现细节仍然模糊不清。通常是hashcode和e