java nio ServerSocketChannel accept是如何工作的?
我搞不懂NIO在幕后是怎么工作的。下面是一个示例代码:java nio ServerSocketChannel accept是如何工作的?,java,sockets,network-programming,nio,nonblocking,Java,Sockets,Network Programming,Nio,Nonblocking,我搞不懂NIO在幕后是怎么工作的。下面是一个示例代码: // Create the server socket channel ServerSocketChannel server = ServerSocketChannel.open(); // nonblocking I/O server.configureBlocking(false); // host-port 8000 server.socket().bind(new java.net.InetSocketAddress(host,80
// Create the server socket channel
ServerSocketChannel server = ServerSocketChannel.open();
// nonblocking I/O
server.configureBlocking(false);
// host-port 8000
server.socket().bind(new java.net.InetSocketAddress(host,8000));
// Create the selector
Selector selector = Selector.open();
// Recording server to selector (type OP_ACCEPT)
server.register(selector,SelectionKey.OP_ACCEPT);
while (true) {
selector.select(); // blocking operation
Iterator it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey selKey = (SelectionKey) it.next();
// THE MOST INTRIGUING PART HERE!!!
if (selKey.isAcceptable()) {
ServerSocketChannel ssChannel = (ServerSocketChannel) selKey.channel();
SocketChannel sc = ssChannel.accept();
}
it.remove();
}
}
这里我有几个问题:
key1 someClient1 acceptable
key2 someClient2 not acceptable
key3 someClient3 acceptable
startThread1
startThread3
scheduler decides to give time to thread3 instead of thread1
thread3 -> socket.accept() <- actually accepts client1
thread1 -> socket.accept() <- actually accepts client3
key1 someClient1可接受
key2 someClient2不可接受
键3某些客户3可接受
开始线程1
开始线程3
调度程序决定将时间分配给thread3而不是thread1
thread3->socket.accept()socket.accept()
selKey.channel()返回一个ServerSocketChannel它与我们在开始时用ServerSocketChannel.open()创建的频道完全相同吗
对
更重要的问题:在大多数其他教程中,selKey.channel();步骤被跳过,它们只使用SocketChannel client=server.accept();例如here:和here:那么,server.accept()如何知道我们处理的当前密钥
没有。他们假设只有一个服务器socketchannel
。你的方法更好:更一般
他们甚至建议接受新线程中的频道
我不知道为什么。这是一个非阻塞呼叫。它将立即返回。这个建议毫无意义。别理它。六年前的教程质量很差,但十三年前有更好的教程。试试Oracle教程。这篇文章的作者似乎根本不理解非阻塞模式的意义。对每一个事件使用单独线程的建议是完全荒谬的。他也不知道如何使用OP_WRITE。他对cancel()
作了错误的断言。我可以继续。他是否执行过这段代码值得怀疑:他肯定没有以任何方式调查它的行为。如何编写不可扩展的NIO服务器。相当了不起
我想可能会出现以下情况
key1 someClient1 acceptable
key2 someClient2 not acceptable
key3 someClient3 acceptable
startThread1
startThread3
scheduler decides to give time to thread3 instead of thread1
thread3 -> socket.accept() <- actually accepts client1
thread1 -> socket.accept() <- actually accepts client3
我甚至不明白为什么要同时在两个线程中接受,更不用说它接受哪个客户端对哪个线程可能有什么影响了。这是一个在不存在的地方发明的难题
所以,您能解释一下选择器是如何与ServerSocketChannel和accept方法成对工作的吗?因为我不明白“接受”以何种顺序接受客户,以及该顺序与所选键的关系
accept()
方法返回待办事项队列中的下一个套接字,并且每当待办事项队列为非空时触发OP_accept。这很简单,没有神秘感。该顺序根本不“与所选关键点相关”。所选键是服务器socketchannel
的键
编辑:看来你有一个重大的误解。考虑:
您可以为OP\u ACCEPT
创建并注册一个ServerSocketChannel
两个客户端同时连接
现在正好有一个SelectionKey
,因此在所选的密钥集中正好有一个:ServerSocketChannel
然后在该键上处理isAcceptable()
大小写;接受一个或两个连接;为OP\u READ注册这些频道。
现在存在三个选择关键点,而在选定关键点集中没有选择关键点,因为您清除了它
两个客户端都发送一些数据
现在,您有两个选择键可以在“选择键集”中读取
好吗
我是否可以简单地执行以下操作:
int availableClients = 0;
while (it.hasNext()) {
SelectionKey selKey = (SelectionKey) it.next();
if (selKey.isAcceptable()) {
++availableClients;
}
it.remove();
}
for (int i = 0; i < availableClients; ++i) {
SocketChannel sc = server.accept();
doSomething(sc);
}
当然可以,但是为什么呢?把简单的东西变成复杂的东西是没有好处的。用第一种方法做。哇!谢谢,这几乎是我想听到的,但在我接受它作为回答之前,我想请您更详细地描述以下句子:“accept()方法返回backlog队列中的下一个套接字,并且每当backlog队列为非空时,OP_uaccept就会激发。”我最后一句关于“++availableClients”的语句只是因为我不明白acceptable key和accept()之间的相关性是什么。看起来我们可以处理一个密钥,但接受另一个客户端,这让我感到困惑。提前谢谢。正确。处理ServerSocketChannel
键,并接受新创建的连接到新客户端的SocketChannel
。相关关系是当OP_uAccept激发时,ACCEPT()
不会返回null
。我的意思是,如果client1有key1,client2有key2,selectedKeys返回[key1,key2],那么serverChannel.ACCEPT()可能会首先为client2创建新频道。然后,当我们处理key2时,它将为client1创建新的通道。所以,我认为顺序实际上是随机的(至少对于非阻塞的东西),我错了吗?什么键?什么客户?你两个都还没有。在您(i)接受连接,然后(ii)注册新的套接字通道之前,客户端没有任何密钥。客户机按其放入待办事项队列的顺序被接受,这取决于完成TCP握手的顺序。“客户机故障”的概念毫无意义。没有两种类型的钥匙,我也没有说过其他的。我说的“客户机密钥”指的是不存在的东西。有一种类型的键:SelectionKey。
有两种类型的频道ServerSocketChannel
和SocketChannel.
我认为这一切都不重要。你在什么地方有个严重的误会,但我无法确定。