NIO網絡編程實例

服務端:

package nioChat;/*
 *@author:
 *@time
 */

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Optional;
import java.util.Set;

public class Server {
    private final static int DEFAULT_PORT = 8888;

    private ServerSocketChannel server;

    private Selector selector;

    private ByteBuffer rBuffer;

    private ByteBuffer wBuffer;

    private Charset charset = Charset.forName("utf-8");

    private int port;

    public Server() {
        this.port = DEFAULT_PORT;
        rBuffer = ByteBuffer.allocate(1024);
        wBuffer = ByteBuffer.allocate(1024);

    }

    public Server(int port) {
        rBuffer = ByteBuffer.allocate(1024);
        wBuffer = ByteBuffer.allocate(1024);
        this.port = port;
    }

    public static void main(String[] args) {
        Server server = new Server(7777);
        server.start();
    }

    public void start() {
        try {
            server = ServerSocketChannel.open();
            server.configureBlocking(false);
            server.socket().bind(new InetSocketAddress(port));
            selector = Selector.open();
            server.register(selector, SelectionKey.OP_ACCEPT);
            Optional.of("服務啓動.")
                    .ifPresent(System.out::println);
            while (true) {
                //一直監聽是否有請求進入
                if (selector.select() > 0) {
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    for (SelectionKey key : selectionKeys) {
                        handles(key);
                    }
                    //處理完後清空select中監聽到的值
                    selectionKeys.clear();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void handles(SelectionKey key) throws IOException {
        //accept事件,與客戶端建立了聯繫
        if (key.isAcceptable()) {
            SocketChannel client = ((ServerSocketChannel) key.channel()).accept();
            //默認阻塞關閉
            client.configureBlocking(false);
            //read事件註冊
            client.register(selector, SelectionKey.OP_READ);
            Optional.of(getClientName(client) + "上線.")
                    .ifPresent(System.out::println);
        }
        //read事件,讀取客戶端發送的消息
        else if (key.isReadable()) {
            SocketChannel client = (SocketChannel) key.channel();
            //接收用戶輸入
            String msg = receive(client);
            //轉發給其他客戶
            if (msg != null && (!msg.equals(""))) {
                send(client, msg);
                client.register(selector, SelectionKey.OP_READ);
                //檢查用戶是否退出
                if (exit(msg)) {
                    Optional.of(getClientName(client) + "下線.")
                            .ifPresent(System.out::println);
                    key.cancel();
                    selector.wakeup();
                }
            }
        }
    }

    private void send(SocketChannel client, String msg) throws IOException {
        Set<SelectionKey> keys = selector.keys();
        for (SelectionKey key : keys) {
            Channel connectedChannel = key.channel();
            if (connectedChannel instanceof ServerSocketChannel) {
                continue;
            }
            if (msg.equals("exit") && client.equals(connectedChannel)) {
                wBuffer.clear();
                wBuffer.put(charset.encode("exit"));
                wBuffer.flip();
                while (wBuffer.hasRemaining()) {
                    ((SocketChannel) connectedChannel).write(wBuffer);
                }
            }
            if (key.isValid() && !client.equals(connectedChannel)) {
                wBuffer.clear();
                wBuffer.put(charset.encode(getClientName(client) + ":" + msg));
                wBuffer.flip();
                while (wBuffer.hasRemaining()) {
                    ((SocketChannel) connectedChannel).write(wBuffer);
                }
            }
        }
    }

    private String receive(SocketChannel client) throws IOException {
        rBuffer.clear();
        while (client.read(rBuffer) > 0) ;
        rBuffer.flip();
        String msg = String.valueOf(charset.decode(rBuffer));
        System.out.println(getClientName(client) + ":" + msg);
        return msg;
    }

    private boolean exit(String msg) {
        if (null != msg && msg.equals("exit")) {
            return true;
        }
        return false;
    }

    private String getClientName(SocketChannel client) {
        return "客戶端[" + client.socket().getPort() + "]";
    }
}

客戶端:

package nioChat;/*
 *@author:
 *@time
 */

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
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.Optional;
import java.util.Set;

public class Client {
    private SocketChannel client;

    private Selector selector;

    private ByteBuffer rBuffer;

    private ByteBuffer wBuffer;

    private String host;

    private int port;

    private boolean isRunning = true;

    private Charset charset = Charset.forName("utf-8");


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

        rBuffer = ByteBuffer.allocate(1024);
        wBuffer = ByteBuffer.allocate(1024);
    }

    public static void main(String[] args) {
        Client client = new Client("localhost", 7777);
        client.start();
    }

    private void start() {
        try {
            client = SocketChannel.open();
            client.configureBlocking(false);
            selector = Selector.open();
            //客戶端監聽連接事件
            client.register(selector, SelectionKey.OP_CONNECT);
            client.connect(new InetSocketAddress(host, port));
            Optional.of("客戶端上線.")
                    .ifPresent(System.out::println);
            //一直監聽是否有請求進入
            while (isRunning) {
                if(selector.select()>0){
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    for (SelectionKey key : selectionKeys) {
                        handles(key);
                    }
                    //處理完後清空select中監聽到的值
                    selectionKeys.clear();
                }

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

    private void handles(SelectionKey key) throws IOException {
        //connect--連接就緒事件
        if (key.isConnectable()) {
            SocketChannel client = (SocketChannel) key.channel();
            if (client.isConnectionPending()) {
                client.finishConnect();
                //處理用戶輸入
                send(client);
            }
            client.register(selector, SelectionKey.OP_READ);
        }
        //read--服務器轉發事件
        else if (key.isReadable()) {
            SocketChannel client = (SocketChannel) key.channel();
            receive(client);
        }
    }

    private void send(SocketChannel client) {
        new Thread(() -> {
            BufferedReader ips = new BufferedReader(new InputStreamReader(System.in));
            while (isRunning) {
                try {
                    String msg = ips.readLine();
                    if (msg != null) {
                        wBuffer.clear();
                        wBuffer.put(charset.encode(msg));
                        wBuffer.flip();
                        while (wBuffer.hasRemaining()) {
                            client.write(wBuffer);
                        }
                        if (msg.equals("exit")) {
                            isRunning = false;
                        }
                    }
                } catch (IOException e) {
                    System.out.println("發送故障.");
                    e.printStackTrace();
                    isRunning = false;
                }
            }
        }).start();
    }

    private String receive(SocketChannel client) throws IOException {
        rBuffer.clear();
        while (client.read(rBuffer) > 0) ;
        rBuffer.flip();
        String msg = String.valueOf(charset.decode(rBuffer));
        if (msg.equals("exit")) {
            isRunning = false;
            Optional.of("客戶端關閉.")
                    .ifPresent(System.out::println);
        } else {
            Optional.of(msg)
                    .ifPresent(System.out::println);
        }
        return msg;
    }

}

 

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