NIO基础通讯

服务端

package com.pw.datastructure.nio;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * @author pw
 * @version 1.0
 * @date 2022/9/1 14:55
 * 服务端
 */
public class NIOServer {
    public static void main(String[] args) throws Exception{
        //1. 创建socket服务通道: ServerSocketChannel  -> ServerSocket (java)
        ServerSocketChannel socketChannel = ServerSocketChannel.open();

        // 2. 创建一个选择器:selector
        Selector selector = Selector.open();

        // 3. 绑定服务端监听端口
        socketChannel.socket().bind(new InetSocketAddress(6666));

        // 4. 设置ServerSocketChannel为非阻塞的
        socketChannel.configureBlocking(false);

        // 5.将ServerSocketChannel 注册进 selector, 设置监听的事件是 ACCEPT (客户端连接时)
        socketChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true){
            // 阻塞1秒selector.select()阻塞多长时间 ,如果有事件发生方法会返回SelectionKey
            if(selector.select(1000) == 0){
                // 在阻塞的1秒内没有客户端连接
                System.out.println("服务器1秒内没有客户端连接~");
                continue;
            }

            // 有客户端进行连接
            // 1. 先拿到注册在selector的选择器集合 SelectionKey
            // 2. 拿到SelectionKey对应的ServerSocketChannel通道
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            // 遍历集合
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()){
                SelectionKey key = iterator.next();
                // 拿到key找到对应的通道,处理相应的事件
                if (key.isAcceptable()){
                    // 如果是连接事件
                    SocketChannel channel = socketChannel.accept();
                    System.out.println("客户端连接成功 生成了一个socketChannel");
                    // channel定义为非阻塞的
                    channel.configureBlocking(false);
                    // 将SocketChannel注册到selector中,关注事件设置为OP_READ,同时给SocketChannel关联传输数据的ByteBuffer
                    channel.register(selector,SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                }
                if (key.isReadable()){
                    // 如果是可读事件
                    // 通过key反向获取对应的channel (这里的channel不需要定义为非阻塞的,因为拿到channel里的数据后直接进行处理)
                    SocketChannel channel = (SocketChannel) key.channel();
                    // 获取channel对应的buffer
                    ByteBuffer buffer = (ByteBuffer) key.attachment();
                    // 获取通道里面的数据
                    channel.read(buffer);
                    System.out.println("客户端发送的数据是:"+new String(buffer.array()) );
                }
                // 手动将集合中移除当前的selectionKey,防止多线程中iterator被重复拿到操作
                iterator.remove();
            }

        }
    }
}

客户端

package com.pw.datastructure.nio;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

/**
 * @author pw
 * @version 1.0
 * @date 2022/9/9 10:38
 */
public class NIOClient {
    public static void main(String[] args) throws Exception {

        // 建立一个网络通道
        SocketChannel socketChannel = SocketChannel.open();
        // 设置成非阻塞通道
        socketChannel.configureBlocking(false);
        // 提供服务器端的ip和端口
        InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 6666);

        // 连接服务器
        if (!socketChannel.connect(inetSocketAddress)){
            // 非阻塞循环
            while (!socketChannel.finishConnect()){
                System.out.println("连接需要事件,客户端非阻塞,可以进行其他工作。。。。");
            }
        }

        // 如果连接成功,就发送数据进行交互。
        String msg = "hello ,socket";
        // ByteBuffer.wrap(包裹):自动识别msg字节数组的大小,创建相同大小的byteBuffer
        ByteBuffer byteBuffer = ByteBuffer.wrap(msg.getBytes());

        // 发送数据,将byteBuffer数据写入到channel中
        socketChannel.write(byteBuffer);
        System.in.read();

    }
}

 

posted @ 2022-09-09 15:57  潘小伟  阅读(32)  评论(0编辑  收藏  举报