JAVA之IO學習(二)NIO聊天室

package main.java.com.founder.study.javaio.socket.nio;

import java.io.Closeable;
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.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Set;

/**
 * Created by yan on 2020/6/30.
 */
public class NioChatServer {

    private   static final int DEFAULT_PORT = 8888;
    private  static final String QUIT = "quit";
    private  static final int BUFFER = 1024;

    private ServerSocketChannel server;
    private Selector selector;
    private ByteBuffer rBuffer = ByteBuffer.allocate(BUFFER);
    private ByteBuffer wBuffer = ByteBuffer.allocate(BUFFER);
    private Charset charset = Charset.forName("UTF-8");
    private int port;

    public NioChatServer(int port){
        this.port = port;

    }
    public NioChatServer(){
            this(DEFAULT_PORT);
    }

    public void start(){

        try {
            server = ServerSocketChannel.open();
            server.configureBlocking(false);
            server.socket().bind(new InetSocketAddress(port));

            selector = Selector.open();
            //把serverSocketChannel的accept監聽事件註冊到selector上
            server.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("啓動服務器監聽端口"+port);

            while(true){
                //阻塞到至少有一個通道在你註冊的事件上就緒了
                //方法返回的int值表示有多少通道已經就緒,是自上次調用select()方法後有多少通道變成就緒狀態
                selector.select();
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                for(SelectionKey key: selectionKeys){
                    //處理被觸發的事件
                    handle(key);

                }
                //處理完事件清空
                selectionKeys.clear();

            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            close(selector);
        }
    }

    private void handle(SelectionKey key) throws IOException {
        //Accept事件 和客戶端建立了連接
        if(key.isAcceptable()){
            ServerSocketChannel server = (ServerSocketChannel)key.channel();
            SocketChannel client = server.accept();
            client.configureBlocking(false);
            client.register(selector,SelectionKey.OP_READ);
            System.out.println("客戶端"+client.socket().getPort()+"建立連接");

        }
        //read事件 客戶端發送了消息
        else if (key.isReadable()){
            SocketChannel client = (SocketChannel)key.channel();
            String fwdMsg = recive(client);
            if(fwdMsg.isEmpty()){
                //客戶端異常
                key.cancel();
                //讓處在阻塞狀態的select()方法立刻返回
                //該方法使得選擇器上的第一個還沒有返回的選擇操作立即返回
                selector.wakeup();
            }else{
                //轉發給其它人
                forwardMessage(client,fwdMsg);
                //檢查用戶是否退出
                if(readeyToQuit(fwdMsg)){
                    key.cancel();
                    selector.wakeup();
                    System.out.println("客戶端"+client.socket().getPort()+"已經斷開");
                }
            }

        }
    }

    private void forwardMessage(SocketChannel client, String fwdMsg) throws IOException {
        for(SelectionKey key: selector.keys()){
            if(key.channel() instanceof ServerSocketChannel){
                    continue;
            }
            if(key.isValid() && !client.equals(key.channel())){
                wBuffer.clear();
                wBuffer.put(charset.encode(fwdMsg));
                wBuffer.flip();
                while (wBuffer.hasRemaining()){
                    ((SocketChannel)key.channel()).write(wBuffer);
                }
            }
        }
    }

    private String recive(SocketChannel client) throws IOException {
        rBuffer.clear();
        while (client.read(rBuffer) > 0);
        rBuffer.flip();
        return String.valueOf(charset.decode(rBuffer));

    }

    public boolean readeyToQuit(String msg){
        return QUIT.equals(msg);
    }

    private static void close(Closeable closeable) {
        try {
            closeable.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        NioChatServer nioChatServer = new NioChatServer(7777);
        nioChatServer.start();
    }
}
package main.java.com.founder.study.javaio.socket.nio;

import java.io.Closeable;
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;
import java.nio.charset.Charset;
import java.util.Set;

/**
 * Created by yanon 2020/6/30.
 */
public class NioChatClient {
    final String QUIT = "quit" ;
    static final  String DEFAULT_SERVER_HOST = "127.0.0.1";
    static  final  int DEFAULT_PORT = 8888;
    private  static final int BUFFER = 1024;
    private SocketChannel client;
    private Selector selector;
    private ByteBuffer rBuffer = ByteBuffer.allocate(BUFFER);
    private ByteBuffer wBuffer = ByteBuffer.allocate(BUFFER);
    private Charset charset = Charset.forName("UTF-8");
    private String host;
    private int port;

    public NioChatClient(){
        this(DEFAULT_SERVER_HOST,DEFAULT_PORT);

    }
    public NioChatClient(String host,int port){
        this.host=host;
        this.port=port;
    }

    public void start(){
        try {
            client = SocketChannel.open();
            client.configureBlocking(false);
            selector = Selector.open();

            client.register(selector, SelectionKey.OP_CONNECT);
            client.connect(new InetSocketAddress(host,port));
            while(true){
                selector.select();
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                for(SelectionKey key: selectionKeys){
                    //處理被觸發的事件
                    handle(key);

                }
                //處理完事件清空
                selectionKeys.clear();

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void handle(SelectionKey key) throws IOException {
        //connet事件 --連接就緒事件
        if(key.isConnectable()){
            SocketChannel client = (SocketChannel)key.channel();

            if(client.isConnectionPending()){
                client.finishConnect();
                //處理用戶的輸入
                new Thread(new UserInputHandler(this)).start();
            }
            client.register(selector,SelectionKey.OP_READ);
        }
        //read事件--服務器轉發消息
        else if(key.isReadable()){
            SocketChannel client = (SocketChannel)key.channel();
            String msg = recive(client);
            if(msg.isEmpty()){
                //服務器異常
                close(selector);
            }else{
                System.out.println(msg);
            }

        }
    }

    private String recive(SocketChannel client) throws IOException {

        rBuffer.clear();
        while(client.read(rBuffer)>0);
        return String.valueOf(charset.decode(rBuffer));

    }

    public void send(String msg) throws IOException {
            wBuffer.clear();
            wBuffer.put(charset.encode(msg));
            wBuffer.flip();
            while(wBuffer.hasRemaining()){
                client.write(wBuffer);

            }
            //檢查用戶是否退出
            if(readeyToQuit(msg)){
                close(selector);
            }
    }

    public boolean readeyToQuit(String msg){
        return QUIT.equals(msg);
    }

    private static void close(Closeable closeable) {
        try {
            closeable.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}
package main.java.com.founder.study.javaio.socket.nio;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * Created by yan on 2020/6/28.
 */
public class UserInputHandler implements Runnable{
    final String QUIT = "quit" ;
        private NioChatClient chatClient;
        public UserInputHandler( NioChatClient chatClient ){
            this.chatClient = chatClient ;
        }
    @Override
    public void run() {
        BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));
        while (true){

            //先發給服務端
            try {
                chatClient.send(consoleReader.readLine());
                chatClient.readeyToQuit(consoleReader.readLine());
            } catch (IOException e) {
                e.printStackTrace();
            }



        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章