我已经阅读了大量的文档、论坛,当然还有你的每一个回复。我已经开发并测试了一个解决方案。这不是最好的,但它是我最好的近似值。
我使用Selector的selectNow()方法。给定一个已注册SocketChannel的命名,我可以使用此方法来了解关联的Socket是否具有可读字节:Selector
selector
public boolean isReadable() {
try {
selector.selectNow();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while(keyIterator.hasNext()) {
SelectionKey selectionKey = keyIterator.next();
if(!selectionKey.isValid()) {
continue;
}
if(selectionKey.isReadable()) {
return true;
}
keyIterator.remove();
}
} catch(IOException e) {
// error
}
return false;
}
这是我发现知道套接字是否具有可读字节而不读取字节的唯一方法。您知道这样做的更好方法或这样做的缺点吗?
编辑:
这个解决方案第一次工作,但它有一个缺点:即使 0 字节是可读的,它也总是返回 true。即使没有数据可用,套接字也可以读取。这不是我想要的行为,因为当读取缓冲区中没有数据时我不想读取。
EDIT2 之二:
测试这段代码:
public static boolean isReadable(Selector selector) {
try {
selector.selectNow();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey selectionKey = keyIterator.next();
if (!selectionKey.isValid()) {
continue;
}
if (selectionKey.isReadable()) {
keyIterator.remove();
return true;
}
keyIterator.remove();
}
} catch (IOException e) {
System.err.println("Error!");
e.printStackTrace();
}
return false;
}
public static void read() {
try {
Selector selector = Selector.open();
SocketChannel socketChannel = SocketChannel.open();
Socket socket = socketChannel.socket();
System.out.println("Connecting to server...");
socket.connect(new InetSocketAddress("localhost", 9999));
System.out.println("Connected to server.");
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
ByteBuffer bb = ByteBuffer.allocate(1024);
while (true) {
boolean readable = isReadable(selector);
if (readable) {
System.out.println("Readable data found! Let's read...");
bb.clear();
int readBytes = socketChannel.read(bb);
if (readBytes < 0) {
System.out.println("End of Stream found");
break;
}
byte[] readArray = new byte[readBytes];
System.arraycopy(bb.array(), 0, readArray, 0, readBytes);
System.out.println("Read (" + (readBytes) + " bytes): "
+ new String(readArray, Charset.forName("UTF-8")));
bb.flip();
socketChannel.write(bb);
Thread.sleep(1000);
} else {
System.out.println("No data to read, sleeping");
Thread.sleep(1000);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
read();
}
首先,我执行一个监听连接并写入数据的应用程序:我使用netcat和这个命令:nc -l 9999
. 然后我执行我的 Java 程序。最后,我可以在其中编写文本行,netcat
并且我的 Java 程序可以完美运行。
请记住,它是概念证明,而不是真正的编程解决方案。事实上,这是一个非常糟糕的做法。谢谢@EJP 和@Markus!