Java Selector 在写入通道后返回带有 OP_READ 的 SelectionKey,而没有无限循环中的数据
我的代码遇到了麻烦:我用 Selector 编写了简单的 SocketChannel 客户端,启动后它成功从服务器读取消息(服务器发送事件)。但是在写入套接字之后(参见 main 方法),选择器开始在无限循环中返回可读套接字,handleKey 返回读取的 -1 个字节,因此选择器始终返回 OP_READ SelectionKey ,而没有要读取的数据。 对不起我的英语。
谢谢。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
public class SelectorTest
{
public SelectorTest() throws IOException {
selector = Selector.open();
}
private void runSelector() {
new Thread(new Runnable() {
public void run()
{
alive = true;
try {
while(alive) {
System.out.println("Selector started...");
selector.select();
Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
while(keyIter.hasNext()) {
SelectionKey key = keyIter.next();
keyIter.remove();
handleKey(key);
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}).start();
}
private void handleKey(SelectionKey key) throws IOException {
SocketChannel chan = (SocketChannel) key.channel();
System.out.println("Processing selected...");
if(key.isConnectable()) {
System.out.println("Connecting ...");
if(chan.finishConnect()) {
key.interestOps(SelectionKey.OP_READ);
} else {
key.channel();
}
} else if(key.isReadable()) {
System.out.println("Processing reading...");
ByteBuffer buf = ByteBuffer.allocate(1024);
int readedBytes = chan.read(buf);
System.out.println("Readed: " + readedBytes);
buf.flip();
for(byte b : buf.array()) {
System.out.print((char) b);
}
} else if(key.isWritable()) {
System.out.println("Finishing writing...");
key.interestOps(SelectionKey.OP_READ);
}
}
public static void main(String[] args) throws IOException {
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(new InetSocketAddress("t1.sis.lan", 6001));
SelectorTest ds = new SelectorTest();
ds.runSelector();
channel.register(ds.selector, SelectionKey.OP_CONNECT);
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for(;;) {
String line = in.readLine();
if(line==null) break;
if(line.toLowerCase().equals("bye")) break;
if (line.toLowerCase().equals("write")) {
String command = "GET_STREAMS\r\n\0";
ByteBuffer buf = ByteBuffer.allocate(1024);
buf.put(command.getBytes());
buf.flip();
channel.write(buf);
}
System.out.println("echo: "+line); // is it alive check
}
ds.alive = false;
ds.selector.wakeup();
channel.close();
}
private Selector selector;
private boolean alive;
}
I've trouble with my code: i've written simple SocketChannel client with Selector, after starting it successfully reads messages from server (server sends events). But after writing to socket (see main method) selector starts returning readable socket in infinyty loop, handleKey returns that -1 bytes readed, so selector all time returns OP_READ SelectionKey without data for reading.
Sorry for my English.
Thanks.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
public class SelectorTest
{
public SelectorTest() throws IOException {
selector = Selector.open();
}
private void runSelector() {
new Thread(new Runnable() {
public void run()
{
alive = true;
try {
while(alive) {
System.out.println("Selector started...");
selector.select();
Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
while(keyIter.hasNext()) {
SelectionKey key = keyIter.next();
keyIter.remove();
handleKey(key);
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}).start();
}
private void handleKey(SelectionKey key) throws IOException {
SocketChannel chan = (SocketChannel) key.channel();
System.out.println("Processing selected...");
if(key.isConnectable()) {
System.out.println("Connecting ...");
if(chan.finishConnect()) {
key.interestOps(SelectionKey.OP_READ);
} else {
key.channel();
}
} else if(key.isReadable()) {
System.out.println("Processing reading...");
ByteBuffer buf = ByteBuffer.allocate(1024);
int readedBytes = chan.read(buf);
System.out.println("Readed: " + readedBytes);
buf.flip();
for(byte b : buf.array()) {
System.out.print((char) b);
}
} else if(key.isWritable()) {
System.out.println("Finishing writing...");
key.interestOps(SelectionKey.OP_READ);
}
}
public static void main(String[] args) throws IOException {
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(new InetSocketAddress("t1.sis.lan", 6001));
SelectorTest ds = new SelectorTest();
ds.runSelector();
channel.register(ds.selector, SelectionKey.OP_CONNECT);
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for(;;) {
String line = in.readLine();
if(line==null) break;
if(line.toLowerCase().equals("bye")) break;
if (line.toLowerCase().equals("write")) {
String command = "GET_STREAMS\r\n\0";
ByteBuffer buf = ByteBuffer.allocate(1024);
buf.put(command.getBytes());
buf.flip();
channel.write(buf);
}
System.out.println("echo: "+line); // is it alive check
}
ds.alive = false;
ds.selector.wakeup();
channel.close();
}
private Selector selector;
private boolean alive;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
read()
在 EOS 上返回 -1,您完全忽略了它。当您获得 EOS 时,您必须关闭通道或至少取消对 OP_READ 的兴趣。否则,当您阅读时,您将永远得到另一个 OP_READ 和另一个 -1 。与上面的评论相反,read()
在空读取时返回零。你可以忽略它,事实上,如果你只在isReadable()
时读取,你甚至看不到它,除非你循环读取,但你不能忽略 EOS。read()
returns -1 at EOS, which you are completely ignoring. When you get EOS, you must either close the channel or at least deregister interest in OP_READ. Otherwise you will just get another OP_READ and another -1 when you read, as you are doing, forever. Contrary to your comments above,read()
returns zero on an empty read. You can ignore that, indeed you won't even see it if you only read whenisReadable()
, unless you read in a loop, but you must not ignore EOS.read() 在读取到 EOF 时返回 -1。定义:
这意味着您应该注销对 OP_READ 的兴趣。
read() returns -1 when it has read EOF. Definition:
This means you should unregister the interest for OP_READ.