Java 在我的客户身上看不到OP_
我是NIO和NIO2的新手。我一直在玩Echo服务器示例代码,它可以完美地工作。我开始写一个类似的客户。我的目标是在一个主线程上运行多个客户端套接字连接 我确实获得了OP_CONNECT,然后选择器不返回并从以下位置超时: 而(选择器。选择(10000)>0){ .... } 如果忽略选择器并开始使用socketChannel.read(…)读取数据,则可以读取数据。所以,数据已经准备好读取了,但是我没有得到选择器。选择(10000)返回一些键 以下是完整的源代码,我非常感谢您的帮助:Java 在我的客户身上看不到OP_,java,client,selector,nio,nio2,Java,Client,Selector,Nio,Nio2,我是NIO和NIO2的新手。我一直在玩Echo服务器示例代码,它可以完美地工作。我开始写一个类似的客户。我的目标是在一个主线程上运行多个客户端套接字连接 我确实获得了OP_CONNECT,然后选择器不返回并从以下位置超时: 而(选择器。选择(10000)>0){ .... } 如果忽略选择器并开始使用socketChannel.read(…)读取数据,则可以读取数据。所以,数据已经准备好读取了,但是我没有得到选择器。选择(10000)返回一些键 以下是完整的源代码,我非常感谢您的帮助: pack
package com.maker.webscraping.nio;
import java.io.IOException;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EchoClient2 {
private static final Logger logger = LoggerFactory.getLogger(EchoClient2.class);
private static final Map<SocketChannel, EchoClient2> mapClients = new ConcurrentHashMap<>();
private static final int DEFAULT_PORT = 5555;
private static final String IP = "127.0.0.1";
private final int clientID;
private final ByteBuffer buffer;
private final SocketChannel socketChannel;
private final CharsetDecoder decoder;
public int getClientID() {
return clientID;
}
public ByteBuffer getBuffer() {
return buffer;
}
public CharsetDecoder getDecoder() {
return decoder;
}
//private static Selector selector = null;
public static void main(String[] args) {
Selector selector = null;
try {
selector = Selector.open();
if (!selector.isOpen())
throw new RuntimeException("Selector closed!");
EchoClient2[] clients = new EchoClient2[2];
clients[0] = new EchoClient2(0, selector);
// wait for incomming events
while (selector.select(10000)>0) {
Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
while (keys.hasNext()) {
SelectionKey key = (SelectionKey) keys.next();
try (SocketChannel socketChannel = (SocketChannel) key.channel()) {
if (key.isConnectable()) {
// connected
logger.info("Client:{} connected!", clients[0].getClientID());
key.interestOps(SelectionKey.OP_READ); // <-- desprete tries
socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); // <-- desprete tries
logger.info("R:{}, W:{}, C:{}, validOps:{}", SelectionKey.OP_READ, SelectionKey.OP_WRITE, SelectionKey.OP_CONNECT, socketChannel.validOps());
// close pending connections
if (socketChannel.isConnectionPending()) {
socketChannel.finishConnect();
}
read(key,selector); // <-- desprete tries
if (key.isReadable()) {
read(key,selector);
}// else if (key.isWritable()) {
// this.writeOP(key);
//}
}
} catch (IOException e) {
logger.error("SocketChannel Exception!", e);
}
}
}
} catch (IOException e) {
logger.error("Selector IOException!", e);
} finally {
try {
selector.close();
} catch (IOException e) {}
}
}
public EchoClient2(int clientID, Selector selector) throws IOException {
this.clientID = clientID;
buffer = ByteBuffer.allocateDirect(2 * 1024);
Charset charset = Charset.defaultCharset();
decoder = charset.newDecoder();
// if (selector==null)
// selector = Selector.open();
socketChannel = SocketChannel.open();
if ((socketChannel.isOpen()) && (selector.isOpen())) {
// configure non-blocking mode
socketChannel.configureBlocking(false);
// set some options
socketChannel.setOption(StandardSocketOptions.SO_RCVBUF,
128 * 1024);
socketChannel.setOption(StandardSocketOptions.SO_SNDBUF,
128 * 1024);
socketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE,
true);
socketChannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ | SelectionKey.OP_WRITE);
//socketChannel.register(selector, SelectionKey.OP_CONNECT);
// connect to remote host
socketChannel.connect(new java.net.InetSocketAddress(IP, DEFAULT_PORT));
// add it to the map
mapClients.put(socketChannel, this);
} else
throw new RuntimeException("Channel or Selector closed!");
}
// isReadable returned true
private static int read(SelectionKey key, Selector selector) {
try {
SocketChannel socketChannel = (SocketChannel) key.channel();
EchoClient2 client = mapClients.get(socketChannel);
ByteBuffer buffer = client.getBuffer();
buffer.clear();
int numRead = -1;
try {
numRead = socketChannel.read(buffer);
} catch (IOException e) {
System.err.println("Cannot read error!");
}
if (numRead == -1) {
mapClients.remove(socketChannel);
System.out.println("Connection closed by: " + socketChannel.getRemoteAddress());
socketChannel.close();
key.cancel();
return 1;
}
if (numRead == 0)
throw new RuntimeException("numRead is 0!!!");
buffer.flip();
CharBuffer charBuffer = client.getDecoder().decode(buffer);
System.out.println("server says:" + charBuffer.toString());
if (buffer.hasRemaining()) {
buffer.compact();
} else {
buffer.clear();
}
int r = new Random().nextInt(100);
//if (r == 50) {
// System.out.println("50 was generated! Close the socket channel!");
// return 1;
//}
ByteBuffer randomBuffer = ByteBuffer.wrap("Random number:".concat(String.valueOf(r))
.getBytes("UTF-8"));
socketChannel.write(randomBuffer);
key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);
socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE); // <-- desprete tries
} catch (IOException e) {
logger.error("IOException inside read!", e);
}
return 0;
}
}
package com.maker.webscraping.nio;
导入java.io.IOException;
导入java.net.StandardSocketOptions;
导入java.nio.ByteBuffer;
导入java.nio.CharBuffer;
导入java.nio.channels.SelectionKey;
导入java.nio.channels.Selector;
导入java.nio.channels.SocketChannel;
导入java.nio.charset.charset;
导入java.nio.charset.CharsetDecoder;
导入java.util.Iterator;
导入java.util.Map;
导入java.util.Random;
导入java.util.concurrent.ConcurrentHashMap;
导入org.slf4j.Logger;
导入org.slf4j.LoggerFactory;
公共类EchoClient2{
私有静态最终记录器Logger=LoggerFactory.getLogger(EchoClient2.class);
私有静态最终映射MapClient=new ConcurrentHashMap();
专用静态最终int默认_端口=5555;
私有静态最终字符串IP=“127.0.0.1”;
私人最终int客户ID;
专用最终字节缓冲区;
私人最终SocketChannel SocketChannel;
专用最终字符集解码器;
public int getClientID(){
返回客户ID;
}
public ByteBuffer getBuffer(){
返回缓冲区;
}
公共字符集解码器getDecoder(){
返回解码器;
}
//私有静态选择器=null;
公共静态void main(字符串[]args){
选择器=null;
试一试{
选择器=selector.open();
如果(!selector.isOpen())
抛出新的RuntimeException(“选择器关闭!”);
EchoClient2[]客户端=新的EchoClient2[2];
客户端[0]=新的EchoClient2(0,选择器);
//等待输入事件
而(选择器。选择(10000)>0){
迭代器键=选择器。selectedKeys()。迭代器();
while(keys.hasNext()){
SelectionKey=(SelectionKey)keys.next();
try(SocketChannel SocketChannel=(SocketChannel)key.channel(){
if(key.isConnectable()){
//连接的
info(“客户端:{}已连接!”,客户端[0].getClientID();
key.interesttops(SelectionKey.OP_READ);//
此代码已经错误。它将在第一次出现选择超时时停止选择。它应该是:
while (selector.isOpen())
{
if (selector.select(10000) > 0)
{
// ...
}
}
还有其他问题
只有当finishConnect()
返回true时,才应假定连接已完成。
连接完成时读取无效。您应该仅在key.isReadable()
为true时读取。您需要单独进行测试,而不是将一个测试附加到isConnectable()
案例中
类似地,iswriteable()也需要单独的大小写。
除非您有要写的内容,否则不应注册OP_WRITE
,最好是在您尝试写入内容时获得零长度返回后注册。OP_WRITE
表示套接字发送缓冲区未满。这几乎总是正确的
您需要在键之后调用键。remove()
。next(),
否则您将一次又一次地获得相同的选定键。选择器不会清除选定的键集
您的评论//关闭挂起的连接
完全不正确
下面的isConnectionPending()
调用是多余的。它当然是挂起的,这就是为什么您得到了OP\u CONNECT。
非常感谢您的帮助和所有这些评论。我的意图是在选择器超时时停止,因为我在客户端,对吗?是的,1)是正确的。2)是的,正如您所看到的,我用“Disprete Trys”注释了代码就在它下面,我正在检查是否可读取,但我从未收到任何通知。3,4)是的,你也在这里,我试图查看我是否收到任何通知,但我没有!5)是的,你完全正确,我不确定我是如何错误地错过了这一次,我认为finishConnect()只有在建立连接后才会返回谢谢,我会根据您的建议更改代码,希望我能开始看到一些notifications@BehzadRe(2)为什么套接字在连接时会神奇地变得可读?它不会,除非服务器已经发送了一些数据。通常,服务器会等待您发送请求,然后发送回复。是的,在很多情况下,您是对的,并不总是这样。在我的情况下,我拥有的测试服务器会发送一个“你好”在OP_接受后立即。我已经按照您的建议修复了代码。谢谢,
while (selector.isOpen())
{
if (selector.select(10000) > 0)
{
// ...
}
}