NIO之网络IO

一个Server 对 一个Client

Client
public class Client {
    public static void main(String[] args) throws Exception {
        // 1. 获取网络通道
        SocketChannel channel = SocketChannel.open();
        // 2. 设置为非阻塞方式
        channel.configureBlocking(false);
        // 3.1 设置服务器 ip 端口
        InetSocketAddress address = new InetSocketAddress("127.0.0.1", 9999);
        // 3.2 连接服务器
        // 连接服务器失败
        if (!channel.connect(address)){
        	// 重新连接服务器失败
            while (!channel.finishConnect()){
                System.out.println("连接服务端同时,做点别的事情");
            }
        }
        // 4. 创建缓冲区,存入数据
        ByteBuffer buffer = ByteBuffer.wrap("hello nio".getBytes());
        // 5. 发送数据
        channel.write(buffer);
        // 连接服务器后防止程序直接结束
        System.in.read();
    }
}
Server
public class Server {
    public static void main(String[] args) throws Exception {
        // 1. 获取 ServerSocketChannel 对象
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 2. 获取 Selector 对象
        Selector selector = Selector.open();
        // 3. 绑定端口号
        serverSocketChannel.bind(new InetSocketAddress(9999));
        // 4. 设置阻塞方式
        serverSocketChannel.configureBlocking(false);

        // 5. 把 channel 注册给 selector 监听有没有客户端连接
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        // 6. selector 开始干活
        while (true) {
            // 6.1 监控客户端判断是否有连接,每隔2秒检测一次
            if (selector.select(2000) == 0) {
                System.out.println("没有client连接, 可以做其他事情。。。");
                continue;
            }
            // 6.2 得到 SelectionKey(代表 Selector 和 ServerSocketChannel 的注册关系) , 判断事件
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()){
                SelectionKey selectionKey = iterator.next();
                // 客户端连接事件发生
                if(selectionKey.isAcceptable()){ 
                    System.out.println("客户端连接事件发生。。。");
                    // 获取连接 channel
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    // 设置为非阻塞
                    socketChannel.configureBlocking(false);
                    // 将 channel 注册到selector,接下来为读事件,传来的数据存到ByteBuffer中
                    socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                }
                // 读取客户端数据事件发生
                if (selectionKey.isReadable()){ 
                	// 从selectionKey中获取 channel
                    SocketChannel channel = (SocketChannel) selectionKey.channel();
                    // 从selectionKey中得到与之关联的数据
                    ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment();
                    // 将数据放入缓冲区
                    channel.read(byteBuffer);
                    System.out.println("客户端发来数据  " + new String(byteBuffer.array()));
                }
                // 6.3 手动从集合中移除当前key,防止重复处理
                iterator.remove();
            }
        }
    }
}

一个Server 对 多个Client

启动 Client

若要启动多个 Client 在 VM Option 中配置 -Dport=端口号

public class TestChat {
    public static void main(String[] args) throws IOException {
        ChatClient chatClient = new ChatClient();
        new Thread(() -> {
            while (true){
                try {
                    chatClient.receiveMsg();
                    Thread.sleep(2000);
                } catch (IOException | InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNextLine()){
            String msg = scanner.nextLine();
            chatClient.sendMsg(msg);
        }
    }
}
ChatClient
public class ChatClient {
    private final String HOST = "127.0.0.1";
    private final int PORT = 9999;
    private SocketChannel socketChannel;
    // ip + 端口
    private String username;

    public ChatClient() throws IOException {
        // 获取 channel
        socketChannel = SocketChannel.open();
        // 设置阻塞方式
        socketChannel.configureBlocking(false);
        // 设置端口号
        InetSocketAddress address = new InetSocketAddress(PORT);
        // 连接服务器
        if (!socketChannel.connect(address)) {
            while (!socketChannel.finishConnect()) {
                System.out.println("...");
            }
        }
        // ip+端口地址作为username
        username = socketChannel.getLocalAddress().toString();
        System.out.println("----------Client (" + username + ") is ready----------");
    }

    // 发送消息
    public void sendMsg(String msg) throws IOException {
        // 发送 stop 时关闭连接
        if (msg.equals("stop")) {
            socketChannel.close();
            return;
        }
        msg = username + "说: " + msg;
        // 将字节数组放入缓冲区中
        ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
        socketChannel.write(buffer);
    }
    
    // 接收消息
    public void receiveMsg() throws IOException {
        // 创建1024大小的buffer
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        int size = socketChannel.read(buffer);
        if (size > 0) {
            // trim() 为去除多余的空格
            System.out.println(new String(buffer.array()).trim());
        }

    }

}
ChatServer
public class ChatServer {
    private ServerSocketChannel listenerChannel;
    private Selector selector;
    private static final int PORT = 9999;

    public ChatServer() {
        try {
            // 1. 获取 channel
            listenerChannel = ServerSocketChannel.open();
            // 2. 获取 selector
            selector = Selector.open();
            // 3. 绑定端口
            listenerChannel.bind(new InetSocketAddress(PORT));
            // 4. 设置阻塞方式
            listenerChannel.configureBlocking(false);
            // 5. 注册监听队列到选择器
            listenerChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start() {
        try {
            // 6. 监听
            while (true) {
                // 6.1 监控客户端判断是否有连接
                if (selector.select(2000) == 0) {
                    System.out.println("server  没有client连接  ...");
                    continue;
                }
                // 6.2 得到 SelectionKey , 判断事件
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

                while (iterator.hasNext()) {
                    SelectionKey selectionKey = iterator.next();
                    // 客户端连接事件
                    if (selectionKey.isAcceptable()) {
                        // 获取客户端 channel
                        SocketChannel socketChannel = listenerChannel.accept();
                        // 设置客户端 channel 阻塞方式
                        socketChannel.configureBlocking(false);
                        // 将客户端 channel 注册到 selector 中, 接下来为读操作
                        socketChannel.register(selector, SelectionKey.OP_READ);
                        System.out.println(socketChannel.getRemoteAddress() + " 上线了!");
                    }
                    // 读取客户端数据事件
                    if (selectionKey.isReadable()) {
                        // 获取消息
                        readMsg(selectionKey);
                    }
                    // 6.3 手动从集合中移除当前key,防止重复处理
                    iterator.remove();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 读取数据
    private void readMsg(SelectionKey selectionKey) throws IOException {
        // 获取通道
        SocketChannel channel = (SocketChannel) selectionKey.channel();
        // 获取缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        // 将数据写入缓冲区
        int size = channel.read(buffer);
        if(size > 0){
            String msg = new String(buffer.array());
            // 控制台打印消息
            printInfo(msg);
            // 发广播给其他客户端
            broadCast(channel, msg);
        }
    }

    // 广播消息给其他客户端
    private void broadCast(SocketChannel except, String msg) throws IOException {
        // 当前 channel 注册在 Selector 上所有的 key
        Set<SelectionKey> keys = selector.keys();
        for (SelectionKey selectionKey : keys) {
            Channel channel =  selectionKey.channel();
            // 排除发送消息的 channel
            if (channel instanceof SocketChannel &&except != channel) {
                SocketChannel destChannel = (SocketChannel) channel;
                ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
                destChannel.write(buffer);
            }

        }
    }


    private void printInfo(String info) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("[" + sdf.format(new Date()) + "] -> " + info);
    }


    public static void main(String[] args) {
        new ChatServer().start();

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值