Java SelectionKey不可写
我很好奇为什么代码总是告诉我“密钥不可写”?我的密码有什么问题吗?每次套接字读取某些内容时,我都将密钥设置为对OP_WRITE感兴趣,并测试它是否可写。然而,它总是说不可写。我完全是Java套接字编程的新手 顺便说一下,我不会关闭客户Java SelectionKey不可写,java,nio,Java,Nio,我很好奇为什么代码总是告诉我“密钥不可写”?我的密码有什么问题吗?每次套接字读取某些内容时,我都将密钥设置为对OP_WRITE感兴趣,并测试它是否可写。然而,它总是说不可写。我完全是Java套接字编程的新手 顺便说一下,我不会关闭客户 public final class DateServer { private DateServer() { throw new IllegalStateException("Instantiation not allowed"); }
public final class DateServer {
private DateServer() {
throw new IllegalStateException("Instantiation not allowed");
}
public static void main(final String[] args) throws Exception {
try (final Selector selector = Selector.open(); ServerSocketChannel serverSocket = ServerSocketChannel.open();) {
InetSocketAddress hostAddress = new InetSocketAddress("127.0.0.1", 9999);
serverSocket.bind(hostAddress);
serverSocket.configureBlocking(false);
serverSocket.register(selector, serverSocket.validOps(), null);
while (true) {
int numSelectedKeys = selector.select();
if (numSelectedKeys > 0) {
handleSelectionKeys(selector.selectedKeys(), serverSocket);
}
}
}
}
private static void handleSelectionKeys(Set<SelectionKey> selectionKeys, ServerSocketChannel serverSocket) throws IOException {
Iterator<SelectionKey> selectionKeyIterator = selectionKeys.iterator();
while (selectionKeyIterator.hasNext()) {
SelectionKey key = selectionKeyIterator.next();
if (key.isAcceptable()) {
acceptClientSocket(key, serverSocket);
} else if (key.isReadable()) {
readRequest(key);
}
selectionKeyIterator.remove();
}
}
private static void acceptClientSocket(SelectionKey key, ServerSocketChannel serverSocket) throws IOException {
SocketChannel client = serverSocket.accept();
client.configureBlocking(false);
client.register(key.selector(), SelectionKey.OP_READ);
System.out.println("Accepted connection from client");
}
private static void readRequest(SelectionKey key) throws IOException {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = client.read(buffer);
if (bytesRead == -1) {
client.close();
} else {
System.out.println(String.format("Request data: %s", new String(buffer.array())));
int interestOps = 0;
interestOps |= SelectionKey.OP_WRITE;
key.interestOps(interestOps);
if (key.isWritable()){
System.out.println("key is writable");
} else {
System.out.println("key is not writable");
}
interestOps = 0;
interestOps |= SelectionKey.OP_READ;
key.interestOps(interestOps);
}
}
}
公共最终类DateServer{
专用数据服务器(){
抛出新的IllegalStateException(“不允许实例化”);
}
公共静态void main(最终字符串[]args)引发异常{
尝试(最终选择器=选择器.open();ServerSocketChannel serverSocket=ServerSocketChannel.open();){
InetSocketAddress主机地址=新的InetSocketAddress(“127.0.0.1”,9999);
绑定(主机地址);
serverSocket.configureBlocking(false);
寄存器(选择器,serverSocket.validOps(),null);
while(true){
int numSelectedKeys=selector.select();
如果(numSelectedKeys>0){
handleSelectionKeys(selector.selectedKeys(),serverSocket);
}
}
}
}
私有静态void handleSelectionKeys(设置selectionKeys、ServerSocketCannel serverSocket)引发IOException{
迭代器selectionKeyIterator=selectionKeys.Iterator();
while(selectionKeyIterator.hasNext()){
SelectionKey=selectionKeyIterator.next();
if(key.isAcceptable()){
acceptClientSocket(密钥、服务器套接字);
}else if(key.isReadable()){
读取请求(密钥);
}
selectionKeyIterator.remove();
}
}
私有静态void acceptClientSocket(SelectionKey key,ServerSocketChannel serverSocket)引发IOException{
SocketChannel client=serverSocket.accept();
client.configureBlocking(false);
client.register(key.selector(),SelectionKey.OP_READ);
System.out.println(“接受来自客户端的连接”);
}
私有静态void readRequest(SelectionKey key)引发IOException{
SocketChannel客户端=(SocketChannel)key.channel();
ByteBuffer缓冲区=ByteBuffer.allocate(1024);
int bytesRead=client.read(缓冲区);
如果(字节读==-1){
client.close();
}否则{
System.out.println(String.format(“请求数据:%s”),新字符串(buffer.array());
int=0;
interesttops |=SelectionKey.OP|u WRITE;
关键字:interestOps(interestOps);
if(key.isWritable()){
System.out.println(“密钥可写”);
}否则{
System.out.println(“密钥不可写”);
}
利率=0;
interesttops |=SelectionKey.OP|u READ;
关键字:interestOps(interestOps);
}
}
}
注册客户端时,只需指定SelectionKey.OP\u READ
,因此频道永远不会准备好写入。(查看Selectionkey.java中的isWritable方法)
在您的情况下,OP_WRITE从未注册,因此无法工作
用这个让它工作
client.register(key.selector(),SelectionKey.OP_READ | SelectionKey.OP_WRITE)代码>按钮只告诉选择器下次要选择什么。设置OP_WRITE不会神奇地使选择键具备预测未来的能力。您必须再次调用select()
,才能根据此代码实际设置OP_WRITE
但是您不需要选择器的“权限”来写入通道。你只需要写,而且只有当写计数为零时,你才需要担心操作写入,正如这里关于该主题的众多答案所示。你的意思是key.interesttops(interesttops)代码>之后不生效?你能解释一下原因吗?好问题。我只是注意到了。我需要调查为什么不起作用。是的,您当前的实现不起作用,因为键选择器当前处于读取模式,而在其处于读取模式时,您不能仅仅添加另一个感兴趣的操作(根据我的调查),并期望在您当前读取时键返回isWriteable()。尽管如此,您仍然可以向channel写入。阅读你有两种方法来修复它1。正如我在回答2中提到的。一旦你读了你需要读的内容,你就把OP_WRITE添加到键中。一个通道总是可以写的,除非它的套接字发送缓冲区中没有空间。没有“处于读取模式”的选择器。回答和评论都是胡说八道。这并不能回答为什么OP正在获取密钥不可写的问题。@Sneh它就是这么做的。把第一段再读一遍。特别是第二句话。@EJP谢谢。我得到了它。如果有任何官方文件解释这一点会更好。我确实在@EJP正确地阅读了你的段落。您编辑并添加了“您必须再次调用select(),以使OP_WRITE能够作为此代码的结果进行实际设置。”这正是您的答案中缺少的部分。而且您还犯了更愚蠢的错误。我没有做任何不正确的陈述。别告诉我该怎么看东西。荣誉
public final boolean isWritable() {
return (readyOps() & OP_WRITE) != 0;
}