我创建了这个异步客户端套接字,它连接到服务器并始终保持连接打开,并在与服务器断开连接时自动重新连接。
无论如何我的问题是:在初始化连接时,我将操作注册为连接操作(SelectionKey.OP_Connect
)。
现在,当我在选择器的选定键之间进行迭代时,我希望它输入控制语句isconnectable并更改操作,如控制语句中所示。
不幸的是,我没有获得任何选定的密钥。我哪里可能出错?
import java.net.InetAddress;
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;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
/*
* @author kewin
*/
public class clientEvent implements Runnable{
private static volatile boolean connected=false;
private SocketChannel channel;
private Selector selector;
private ByteBuffer readBuffer = ByteBuffer.allocate(8192);
private QueueData Qdata;
private SelectionKey selectKey;
private void initiateConnection() {
try {
selector= Selector.open();//initializes the Selector Thread
channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(new InetSocketAddress(InetAddress.getByName("127.0.0.1"),2000));
Thread.sleep(50);//Sleeps for a few Seconds to allow decent connection completion
channel.register(selector,SelectionKey.OP_CONNECT);//Registers the channel with the a selector and a selection key
if(channel.finishConnect())/*checks whether the connection is finished*/{
channel.register(selector,SelectionKey.OP_READ);//Registers the channel with the a selector and a selection key
connected=true;}
} catch(Exception ex){connected=false;}
}
private void ConnectAndMonitor(){
while(true){
try {
readBuffer.clear();
channel.read(readBuffer);
} catch (Exception ex) {
connected=false
try {
channel.close()
selector.close();
} catch (Exception e) {
}
if(!connected){
initiateConnection();
connected=true;
}
}
}
}
@Override
public void run() {
try{
new Thread(){@Override public void run(){ConnectAndMonitor()}}.start();
while(true){
if(!connected){
System.out.println("not connected");
Thread.sleep(500);
}
else{
selector.selectNow();
Set Keys=selector.keys();
Iterator iterator =Keys.iterator();
while(iterator.hasNext()){
SelectionKey key=(SelectionKey)iterator.next();
if(key.isConnectable()){
channel.register(selector,SelectionKey.OP_READ);
System.out.println("Connectable");
break;
}
if(key.isReadable()){
channel.register(selector,SelectionKey.OP_WRITE);
System.out.println("Readable");
break;
}
if(key.isWritable()){
channel.register(selector,SelectionKey.OP_CONNECT);
System.out.println("Writable");
break;
}
System.out.println("<<<<<<<<<>>>>>>>>>>>>");
}
Thread.sleep(1000);
}
}
}
catch(Exception ex){
}
}
public static void main(String[] args){
new Thread(new clientEvent()).start();
}
}
答案 0 :(得分:1)
如果你在阻塞模式下进行连接,它会在方法调用期间阻塞并完成,所以如果你随后为OP_CONNECT注册它,isConnectable()
永远不会成为真。
因此,如果你必须有非阻塞连接,你的代码已经没有,那么首先将通道置于非阻塞模式,发出connect()
,注册OP_CONNECT ,然后当它触发和`finishConnect()返回true时,取消注册OP_CONNECT并注册其他内容,或者因为你是一个客户端更可能只是开始发送请求。
编辑:您编辑的代码在以下方面不正确:
Thread.sleep()
。finishConnect()
调用移至您选择循环的isConnected()
个案例。OP_CONNECT/isConnectable()
触发时,取消注册 OP_CONNECT。if(!connected)
测试。我上面已经说过的大部分内容。目前你是(a)给出连接时间,(b)完成它,(c)在选择循环中等待它完成,(d)永远不要注销OP_CONNECT
即使你不是对此感兴趣,(e)如果没有连接,则永远不执行select(),以及(f)尝试在select()循环中查找已完成的连接。这没有任何意义。
另一方面,如果您不介意等待连接完成内联创建它,为什么要在非阻塞模式下呢?在阻止模式下执行,然后configureBlocking(false),
注册OP_READ/OP_WRITE
并完全忘记OP_CONNECT
,isConnectable()
和finishConnect()
。