创建阻塞的 EchoClient

客户程序一般不需要同时建立与服务器的多个连接,因此用一个线程,按照阻塞模式运行就能满足需求

public class EchoClient {        private SocketChannel socketChannel = null;        public EchoClient() throws IOException {        socketChannel = SocketChannel.open();        InetAddress ia = InetAddress,getLocalHost();        InetSocketAddress isa = new InetSocketAddress(ia,8000);        socketChannel.connect(isa); //连接服务器    }        public static void main(String args[])throws IOException {        new EchoClient().talk();    }        private PrintWriter getWriter(Socket socket) throws IOException {        OutputStream socketOut = socket.getOutputStream();        return new PrintWriter(socketOut,true);    }        private BufferedReader getReader(Socket socket) throws IOException {        InputStream socketIn = socket.getInputStream();        return new BufferedReader(new InputStreamReader(socketIn));    }        public void talk() throws IOException {        try {            BufferedReader br = getReader(socketChannel.socket());            PrintWriter pw = getWriter(socketChannel.socket());                        BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in));                        String msq = null;                        while((msg = localReader.readLine()) != null) {                pw.println(msg);                System.out.println(br.readLine());                if(msq.equals("bye")) {                    break;                }            }        } catch(IOException e) {            e.printStackTrace();        } finally {            try {                socketChannel.close();            } catch(IOException e) {                e.printStackTrace();            }        }    }}

创建非阻塞的 EchoClient

对于客户与服务器之间的通信,按照它们收发数据的协调程度来区分,可分为同步通信和异步通信

同步通信指甲方向乙方发送了一批数据后,必须等接收到了乙方的响应数据后,再发送下一批数据。同步通信要求一个 IO 操作完成之后,才能完成下一个 IO 操作,用阻塞模式更容易实现

异步通信指发送数据和接收数据的操作互不干扰,各自独立进行。异步通信允许发送数据和接收数据的操作各自独立进行,用非阻塞模式更容易实现

值得注意的是,通信的两端并不要求都采用同样的通信方式,当一方采用同步通信时,另一方可以采用异步通信

public class EchoClient {        private SocketChannel socketChannel = null;    private ByteBuffer sendBuffer = ByteBuffer.allocate(1024);    private ByteBuffer receiveBuffer = ByteBuffer.allocate(1024);    private Charset charset = Charset.forName("GBK");    private Selector selector;        public EchoClient() throws IOException {        socketChannel = SocketChannel.open();        InetAddress ia = InetAddress.getLocalHost();        InetSocketAddress isa = new InetSocketAddress(ia, 8000);        socketChannel.connect(isa); //采用阻塞模式连接服务器        socketChannel.configureBlocking(false); //设置为非阻塞模式        selector = Selector.open();    }        public static void main(String args[]) throws IOException {        final EchoClient client = new EchoClient();        Thread receiver=new Thread() {         public void run() {                client.receiveFromUser(); //接收用户向控制台输入的数据            }           };        receiver.start();        client.talk();    }        /** 接收用户从控制台输入的数据,放到sendBuffer中 */    public void receiveFromUser() {        try {            BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in));            String msg = null;            while((msg = localReader.readLine()) != null) {                synchronized(sendBuffer) {                    sendBuffer.put(encode(msg + "\r\n"));                }                if (msg.equals("bye")) {                    break;                }            }        } catch(IOException e) {            e.printStackTrace();        }    }        //接收和发送数据    public void talk() throws IOException {        socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);        while (selector.select() > 0 ) {            Set readyKeys = selector.selectedKeys();            Iterator it = readyKeys.iterator();            while (it.hasNext()) {                SelectionKey key = null;                try {                    key = (SelectionKey) it.next();                    it.remove();                    if (key.isReadable()) {                        receive(key);                    }                    if (key.isWritable()) {                        send(key);                    }                } catch(IOException e) {                    e.printStackTrace();                    try {                        if(key != null) {                            key.cancel();                            key.channel().close() ;                        }                    } catch(Exception ex) {                        e.printStackTrace();                    }                }            }        }    }        public void send(SelectionKey key) throws IOException {        //发送sendBuffer的数据        SocketChannel socketChannel = (SocketChannel)key.channel();        synchronized(sendBuffer) {            sendBuffer.flip(); //把极限设为位置,把位置设为0            socketChannel.write(sendBuffer); //发送数据            sendBuffer.compact(); //删除已经发送的数据        }    }        public void receive(SelectionKey key) throws IOException {        //接收EchoServer发送的数据,把它放到receiveBuffer        //如果receiveBuffer有一行数据,就打印这行数据,然后把它从receiveBuffer删除        SocketChannel socketChannel = (SocketChannel) key.channel();        socketChannel.read(receiveBuffer):                receiveBuffer.flip();        String receiveData = decode (receiveBuffer);                if(receiveData.indexOf("\n") == -1) return;                String outputData = receiveData.substring(0, receiveData.indexOf("\n") + 1):                System.out.print(outputData);                if(outputData.equals("echo:bye\r\n")) {            key.cancel():            socketChannel.close();            selector.close();            System.exit(0);        }                ByteBuffer temp = encode(outputData);        receiveBuffer.position(temp.limit());        receiveBuffer.compact(): //删除已经打印的数据    }        //解码    public String decode(ByteBuffer buffer) {         CharBuffer charBuffer= charset.decode(buffer);        return charBuffer.toString();    }        //编码public ByteBuffer encode(String str) {        return charset.encode(str);    }}