简短地说,不。
available()是不可靠的(至少对我来说不是)。我建议
java.nio.channels.SocketChannel与
Selector和一起使用
SelectionKey。该解决方案在某种程度上基于事件,但是比普通套接字更加复杂。
对于客户:
- 构造套接字通道(
socket
),打开选择器(selector = Selector.open();
)。 - 使用非阻塞
socket.configureBlocking(false);
- 注册连接器选择器
socket.register(selector, SelectionKey.OP_CONNECT);
- 连接
socket.connect(new InetSocketAddress(host, port));
- 看看是否有新东西
selector.select();
- 如果“新”表示成功连接,则为
OP_READ
; 注册选择器。如果“新”指的是可用数据,则只需从套接字读取。
但是,为了使其异步,您需要设置一个单独的线程(尽管套接字被创建为非阻塞的,但无论如何该线程都会阻塞),以检查是否已到达某些线程。
对于服务器,这里有
ServerSocketChannel您使用的服务器
OP_ACCEPT。
供参考,这是我的代码(客户端),应给您提示:
private Thread readingThread = new ListeningThread(); private class ListeningThread extends Thread { public void run() { running = true; try { while(!close) listen(); messenger.close(); } catch(ConnectException ce) { donotifyConnectionFailed(ce); } catch(Exception e) {// e.printStackTrace(); messenger.close(); } running = false; } } public void connect(String host, int port) { try { SocketChannel socket = SocketChannel.open(); socket.configureBlocking(false); socket.register(this.selector, SelectionKey.OP_CONNECT); socket.connect(new InetSocketAddress(host, port)); } catch(IOException e) { this.donotifyConnectionFailed(e); } } protected void listen() throws IOException { // see if there are any new things going on this.selector.select(); // process events Iterator<SelectionKey> iter = selector.selectedKeys().iterator(); while(iter.hasNext()) { SelectionKey key = iter.next(); iter.remove(); // check validity if(key.isValid()) { // if connectable... if(key.isConnectable()) { // ...establish connection, make messenger, and notify everyone SocketChannel client = (SocketChannel)key.channel(); // now this is tricky, registering for OP_READ earlier causes the selector not to wait for incoming bytes, which results in 100% cpu usage very, very fast if(client!=null && client.finishConnect()) { client.register(this.selector, SelectionKey.OP_READ); } } // if readable, tell messenger to read bytes else if(key.isReadable() && (SocketChannel)key.channel()==this.messenger.getSocket()) { // read message here } } } } public void start() { // start a reading thread if(!this.running) { this.readingThread = new ListeningThread(); this.readingThread.start(); } } public void close() { this.close = true; }对于服务器:
public ChannelMessageServer(int port) throws IOException { this.server = ServerSocketChannel.open(); this.server.configureBlocking(false); this.server.socket().bind(new InetSocketAddress(port)); this.server.register(this.selector, SelectionKey.OP_ACCEPT); } protected void listen() throws IOException { // see if there are any new things going on this.selector.select(); // process events Iterator<SelectionKey> iter = selector.selectedKeys().iterator(); while(iter.hasNext()) { SelectionKey key = iter.next(); // do something with the connected socket iter.remove(); if(key.isValid()) this.process(key); } } protected void process(SelectionKey key) throws IOException { // if incoming connection if(key.isAcceptable()) { // get client SocketChannel client = (((ServerSocketChannel)key.channel()).accept()); try { client.configureBlocking(false); client.register(this.selector, SelectionKey.OP_READ); } catch(Exception e) { // catch } } // if readable, tell messenger to read else if(key.isReadable()) { // read } }希望这可以帮助。



