鍍金池/ 問答/Java  網(wǎng)絡(luò)安全/ java.nio.channels.NotYetConnectedExcepti

java.nio.channels.NotYetConnectedException

問題描述:

服務(wù)端已啟動,端口9999。
客戶端通過Channel方式實現(xiàn),功能一切正常。
客戶端通過Selector+Channel方式實現(xiàn),程序報錯。
哪位兄臺遇到過此問題,請賜教
Exception in thread "main" java.nio.channels.NotYetConnectedException
    at sun.nio.ch.SocketChannelImpl.ensureWriteOpen(SocketChannelImpl.java:269)
    at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:474)
    at demo.nio.SelectorDemo.run(SelectorDemo.java:55)
    at demo.nio.SelectorDemo.main(SelectorDemo.java:24)

服務(wù)端代碼:

package demo.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

/**  
 * @ClassName: ServerSocketChannel  
 * @Description: 
 * @author 
 * @date 2018年1月24日 下午9:53:15  
 *    
 */
public class ServerSocketChannelDemo implements Runnable {
    public static void main(String[] args) {
        ServerSocketChannelDemo serverSocketChannelDemo = new ServerSocketChannelDemo();
        serverSocketChannelDemo.run();
    }
    
    public void run() {
        try {
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.socket().bind(new InetSocketAddress(9999));
            serverSocketChannel.configureBlocking(false);
            
            while(true){
                SocketChannel socketChannel = serverSocketChannel.accept();
                if(socketChannel != null){
                    //do something with socketChannel...
                    ByteBuffer buf1 = ByteBuffer.allocate(10000);
                    socketChannel.read(buf1);
                    buf1.flip();
                    if(buf1.hasRemaining())
                        System.out.println(">>>服務(wù)端收到數(shù)據(jù):"+new String(buf1.array()));
                    buf1.clear();
                    
                    ByteBuffer buf2 = ByteBuffer.allocate(10000);
                    buf2.put("A word from server!".getBytes());
                    buf2.flip();
                    socketChannel.write(buf2);
                    
                    socketChannel.close();
                }else{
                    Thread.sleep(3000);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

客戶端代碼(Channel實現(xiàn)):

package demo.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;

/**  
 * @ClassName: SocketChannelDemo  
 * @Description: 
 * @author 
 * @date 2018年1月11日 下午10:01:40  
 *    
 */
public class SocketChannelDemo implements Runnable{
    public static void main(String[] args) {
        SocketChannelDemo socketChannelDemo = new SocketChannelDemo();
        socketChannelDemo.run();
    }

    public void run() {
        try {
            //通道
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.connect(new InetSocketAddress("127.0.0.1", 9999));
            while(!socketChannel.finishConnect()){
                wait(1000);
            }
            //緩沖區(qū)
            ByteBuffer buf1 = ByteBuffer.allocate(10000);
            buf1.put("A word from client!".getBytes());
            buf1.flip();
            if(buf1.hasRemaining())
                socketChannel.write(buf1);
            buf1.clear();
            
            ByteBuffer buf2 = ByteBuffer.allocate(10000);
            socketChannel.read(buf2);
            if(buf2.hasRemaining())
                System.out.println(">>>客戶端接收數(shù)據(jù):"+new String(buf2.array()));
            buf2.clear();
            
            socketChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

客戶端代碼(Selector+Channel實現(xiàn)):

package demo.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Set;
import java.util.Iterator;

/**  
 * @ClassName: SelectorDemo  
 * @Description:  
 * @author 
 * @date 2018年1月12日 下午9:06:21  
 *    
 */
public class SelectorDemo implements Runnable{
    public static void main(String[] args) {
        SelectorDemo selectorDemo = new SelectorDemo();
        selectorDemo.run();
    }

    public void run() {
        try {
            //選擇器
            Selector selector = Selector.open();
            //通道
            SocketChannel socketChannel1 = SocketChannel.open();
            socketChannel1.configureBlocking(false);
            SelectionKey key1 = socketChannel1.register(selector, SelectionKey.OP_CONNECT);
            socketChannel1.connect(new InetSocketAddress("127.0.0.1", 9999));
            
            while(true){
                int readyChannels = selector.selectNow();//selectNow()非阻塞,select(timeout)和select()阻塞
                if(readyChannels == 0)
                    continue;
                //selector.wakeup();//第一個線程調(diào)用select后,需要執(zhí)行此方法,阻塞在select上的線程會立馬返回。
                Set<?> selectedKeys = selector.selectedKeys();
                Iterator<?> keyIterator = selectedKeys.iterator();
                while(keyIterator.hasNext()){
                    SelectionKey key = (SelectionKey) keyIterator.next();
                    if(key.isAcceptable()){
                        // a connection was accepted by a ServerSocketChannel.
                        ServerSocketChannel socketchannel = (ServerSocketChannel) key.channel();
                    }else if(key.isConnectable()){
                        // a connection was established with a remote server.
                        SocketChannel socketchannel = (SocketChannel) key.channel();
                        ByteBuffer buf1 = ByteBuffer.allocate(10000);
                        buf1.put("A word from client!".getBytes());
                        buf1.flip();
                        socketchannel.write(buf1);
                        buf1.clear();
                        
                        ByteBuffer buf2 = ByteBuffer.allocate(10000);
                        socketchannel.read(buf2);
                        buf2.flip();
                        System.out.println(">>>客戶端接收數(shù)據(jù):"+new String(buf2.array()));
                        buf2.clear();
                    }else if(key.isReadable()){
                        // a channel is ready for reading.
                        SelectableChannel fileChannel = key.channel();
                    }else if(key.isWritable()){
                        // a channel is ready for writing.
                        SelectableChannel fileChannel = key.channel();
                    }
                    keyIterator.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
回答
編輯回答
蟲児飛
package demo.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Set;
import java.util.Iterator;

/**  
 * @ClassName: SelectorDemo  
 * @Description:  
 * @author 
 * @date 2018年1月12日 下午9:06:21  
 *    
 */
public class SelectorDemo implements Runnable{
    public static void main(String[] args) {
        SelectorDemo selectorDemo = new SelectorDemo();
        selectorDemo.run();
    }

    public void run() {
        try {
            //選擇器
            Selector selector = Selector.open();
            //通道
            SocketChannel socketChannel1 = SocketChannel.open();
            socketChannel1.configureBlocking(false);
            SelectionKey key1 = socketChannel1.register(selector, SelectionKey.OP_CONNECT);
            socketChannel1.connect(new InetSocketAddress("127.0.0.1", 9999));
            
            while(true){
                int readyChannels = selector.selectNow();//selectNow()非阻塞,select(timeout)和select()阻塞
                if(readyChannels == 0)
                    continue;
                //selector.wakeup();//第一個線程調(diào)用select后,需要執(zhí)行此方法,阻塞在select上的線程會立馬返回。
                Set<?> selectedKeys = selector.selectedKeys();
                Iterator<?> keyIterator = selectedKeys.iterator();
                while(keyIterator.hasNext()){
                    SelectionKey key = (SelectionKey) keyIterator.next();
                    if(key.isAcceptable()){
                        // a connection was accepted by a ServerSocketChannel.
                        ServerSocketChannel socketchannel = (ServerSocketChannel) key.channel();
                    }else if(key.isConnectable()){
                        // a connection was established with a remote server, false.
                        //Now is Connectable(可連接,但是未必已經(jīng)連接完成)
                         try {
                           socketchannel.finishConnect();//如果是非阻塞模式,可能要循環(huán)詢問
                        } catch (Exception e) {}
                        
                        
                        SocketChannel socketchannel = (SocketChannel) key.channel();
                        ByteBuffer buf1 = ByteBuffer.allocate(10000);
                        buf1.put("A word from client!".getBytes());
                        buf1.flip();
                        socketchannel.write(buf1);
                        buf1.clear();
                        
                        ByteBuffer buf2 = ByteBuffer.allocate(10000);
                        socketchannel.read(buf2);
                        buf2.flip();
                        System.out.println(">>>客戶端接收數(shù)據(jù):"+new String(buf2.array()));
                        buf2.clear();
                    }else if(key.isReadable()){
                        // a channel is ready for reading.
                        SelectableChannel fileChannel = key.channel();
                    }else if(key.isWritable()){
                        // a channel is ready for writing.
                        SelectableChannel fileChannel = key.channel();
                    }
                    keyIterator.remove();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

題主的英文好像不錯,可以點進SocketChannel.finishConnect()方法里面看下注釋

2017年7月27日 11:06