gpt4 book ai didi

从未选择用于多个 OP 代码的 Java SocketChannel register()

转载 作者:塔克拉玛干 更新时间:2023-11-01 22:31:08 24 4
gpt4 key购买 nike

我用 Java 构建了一个基于选择器的系统,可以接受多个客户端。它有一个在 OP_ACCEPT 下注册的 ServerSocketChannel,它接受传入的连接并再次向选择器注册生成的 SocketChannel。这是一点:

ServerSocketChannel insock = ServerSocketChannel.open();
insock.configureBlocking(false);
insock.socket().bind(new InetSocketAddress(6789));

Selector sel = Selector.open();
SelectionKey joinchannel = insock.register(sel, SelectionKey.OP_ACCEPT);

System.out.println("Ready to accept incoming connections.");

while (true) {
int ready = sel.selectNow();
if (ready == 0)
continue;
Set<SelectionKey> selectedKeys = sel.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if(key.isAcceptable()){
SocketChannel newConnection = insock.accept();
System.out.println("New client "+newConnection+" connected.");
newConnection.configureBlocking(false);
newConnection.register(sel, SelectionKey.OP_READ).attach(new DGPlayer());
}

如果我为 OP_READ 注册新的 SocketChannel,这工作正常。 isReadable() 检查成功,读取数据。这是一点:

else if(key.isReadable()){
ByteBuffer buf = ByteBuffer.allocate(1024);
int trans = ((SocketChannel)key.channel()).read(buf); buf.flip();
byte[] ba = new byte[buf.remaining()]; buf.get(ba);
String msg = new String(ba, 0, ba.length, Charset.forName("UTF-8"));

if(trans > 0){
DGPlayer client = (DGPlayer) key.attachment();
System.out.println(client.name+": "+msg.trim());
}
}
// else if(key.isWritable()){
// ByteBuffer buf = ByteBuffer.allocate(48);
// buf.clear();
// buf.put(((String)key.attachment()).getBytes());
// buf.flip();
//
// SocketChannel target = ((SocketChannel)key.channel());
// while(buf.hasRemaining()) {
// target.write(buf);
// }
//
// key.attach(null);
// }

但是,如果我为 OP_READ|OP_WRITE 注册 SocketChannel,则什么也没有发生。据我所知,选择器从未发现 channel 是 readable() 或 writable()。唯一的变化是注册 channel 以获得 WRITE 权限。

知道为什么会这样吗?

编辑 - 为了完成,这里有一些客户端代码:

while (true) {
int readyChannels = sel.select();
if (readyChannels == 0)
continue;

Set<SelectionKey> selectedKeys = sel.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();

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

if (key.isReadable()) {
ByteBuffer buf = ByteBuffer.allocate(1024);
int trans = ((SocketChannel)key.channel()).read(buf); buf.flip();
byte[] ba = new byte[buf.remaining()]; buf.get(ba);
String msg = new String(ba, 0, ba.length, Charset.forName("UTF-8"));

if(msg.trim().length() != 0)
System.out.println("Response from server: "+msg.trim());
}
else if(key.isWritable() && messages.size() > 0){
String message = messages.remove();
ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(message.getBytes(Charset.forName("UTF-8")));

buf.flip();

int written = outsock.write(buf);
while(buf.hasRemaining()){
outsock.write(buf);
}

System.out.println("Wrote '"+message+"' to server");
}
keyIterator.remove();
}
}

(客户端为 OP_READ|OP_WRITE 注册服务器)

最佳答案

一般来说,如果您没有任何要主动写入的内容,那么为 OP_WRITE 注册一个 channel 是个坏主意。大多数 channel 大部分时间都可以写入,因此每次调用 Selector.select 都会无阻塞地返回并消耗资源。最好在SelectionKey.interestOps中加上writing flag当您准备好向 channel 写入内容时,并在完成后删除标志。

关于从未选择用于多个 OP 代码的 Java SocketChannel register(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10940654/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com