java socketNIO demo

先启动server 再启动client

package learn.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
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.HashMap;
import java.util.Map;
import java.util.Set;

public class NIOSServer {
    private int port = 8888;

    // 解码buffer
    private Charset cs = Charset.forName("utf-8");

    /* 接受数据缓冲区 */
    private static ByteBuffer sBuffer = ByteBuffer.allocate(1024);

    /* 发送数据缓冲区 */
    private static ByteBuffer rBuffer = ByteBuffer.allocate(1024);

    /* 映射客户端channel */
    private Map<String, SocketChannel> clientsMap = new HashMap<String, SocketChannel>();

    private static Selector selector;

    public NIOSServer(int port) {
        this.port = port;
        try {
            init();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void init() throws IOException {
        /*
         * 启动服务器端,配置为非阻塞,绑定端口,注册accept事件 ACCEPT事件:当服务端收到客户端连接请求时,触发该事件
         */
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);
        ServerSocket serverSocket = serverSocketChannel.socket();
        serverSocket.bind(new InetSocketAddress(port));
        selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("server start on port:" + port);
    }

    /**
     * 服务器端轮询监听,select方法会一直阻塞直到有相关事件发生或超时
     */
    private void listen() {
        while (true) {
            try {
                selector.select();// 返回值为本次触发的事件数
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                for (SelectionKey key : selectionKeys) {
                    handle(key);
                }
                selectionKeys.clear();// 清除处理过的事件
            } catch (Exception e) {
                e.printStackTrace();
                break;
            }

        }
    }

    /**
     * 处理不同的事件
     */
    private void handle(SelectionKey selectionKey) throws IOException {
        ServerSocketChannel server = null;
        SocketChannel client = null;
        String receiveText = null;
        int count = 0;
        if (selectionKey.isAcceptable()) {
            /*
             * 客户端请求连接事件 serversocket为该客户端建立socket连接,将此socket注册READ事件,监听客户端输入
             * READ事件:当客户端发来数据,并已被服务器控制线程正确读取时,触发该事件
             */
            server = (ServerSocketChannel) selectionKey.channel();
            client = server.accept();
            client.configureBlocking(false);
            client.register(selector, SelectionKey.OP_READ);
        } else if (selectionKey.isReadable()) {
            /*
             * READ事件,收到客户端发送数据,读取数据后继续注册监听客户端
             */
            client = (SocketChannel) selectionKey.channel();
            rBuffer.clear();
            count = client.read(rBuffer);
            if (count > 0) {
                rBuffer.flip();
                receiveText = String.valueOf(cs.decode(rBuffer).array());
                System.out.println(client.toString() + ":" + receiveText);
                dispatch(client, receiveText);
                client = (SocketChannel) selectionKey.channel();
                // client.register(selector, SelectionKey.OP_READ);
            }
        }
    }

    /**
     * 把当前客户端信息 推送到其他客户端
     */
    private void dispatch(SocketChannel client, String info) throws IOException {
        Socket s = client.socket();
        String name = "[" + s.getInetAddress().toString().substring(1) + ":" + Integer.toHexString(client.hashCode())
                + "]";
        if (!clientsMap.isEmpty()) {
            for (Map.Entry<String, SocketChannel> entry : clientsMap.entrySet()) {
                SocketChannel temp = entry.getValue();
                if (!client.equals(temp)) {
                    sBuffer.clear();
                    sBuffer.put((name + ":" + info).getBytes());
                    sBuffer.flip();
                    // 输出到通道
                    temp.write(sBuffer);
                }
            }
        }
        clientsMap.put(name, client);
    }

    public static void main(String[] args) throws IOException {
        NIOSServer server = new NIOSServer(7777);
        server.listen();
    }
}

client

package learn.nio;

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.util.Date;
import java.util.Scanner;
import java.util.Set;

public class NIOSClient {
    /* 发送数据缓冲区 */
    private static ByteBuffer sBuffer = ByteBuffer.allocate(1024);

    /* 接受数据缓冲区 */
    private static ByteBuffer rBuffer = ByteBuffer.allocate(1024);

    /* 服务器端地址 */
    private InetSocketAddress SERVER;

    private static Selector selector;

    private static SocketChannel client;

    private static String receiveText;

    private static String sendText;

    private static int count = 0;

    public NIOSClient(int port) {
        SERVER = new InetSocketAddress("localhost", port);
        init();
    }

    public void init() {
        try {
            /*
             * 客户端向服务器端发起建立连接请求
             */
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
            selector = Selector.open();
            socketChannel.register(selector, SelectionKey.OP_CONNECT);
            socketChannel.connect(SERVER);
            /*
             * 轮询监听客户端上注册事件的发生
             */
            while (true) {
                selector.select();
                Set<SelectionKey> keySet = selector.selectedKeys();
                for (final SelectionKey key : keySet) {
                    handle(key);
                }
                ;
                keySet.clear();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        new NIOSClient(7777);
    }

    private void handle(SelectionKey selectionKey) throws IOException {
        if (selectionKey.isConnectable()) {
            /*
             * 连接建立事件,已成功连接至服务器
             */
            client = (SocketChannel) selectionKey.channel();
            if (client.isConnectionPending()) {
                client.finishConnect();
                System.out.println("connect success !");
                sBuffer.clear();
                sBuffer.put((new Date() + " connected!").getBytes());
                sBuffer.flip();
                client.write(sBuffer);// 发送信息至服务器
                /*
                 * 原文来自站长网 启动线程一直监听客户端输入,有信息输入则发往服务器端 因为输入流是阻塞的,所以单独线程监听
                 */
                new Thread() {
                    @Override
                    public void run() {
                        while (true) {
                            try {
                                sBuffer.clear();
                                Scanner cin = new Scanner(System.in);
                                sendText = cin.nextLine();
                                System.out.println(sendText);
                                /*
                                 * 未注册WRITE事件,因为大部分时间channel都是可以写的
                                 */
                                sBuffer.put(sendText.getBytes("utf-8"));
                                sBuffer.flip();
                                client.write(sBuffer);
                            } catch (IOException e) {
                                e.printStackTrace();
                                break;
                            }
                        }
                    };
                }.start();
            }
            // 注册读事件
            client.register(selector, SelectionKey.OP_READ);
        } else if (selectionKey.isReadable()) {
            /*
             * 读事件触发 有从服务器端发送过来的信息,读取输出到屏幕上后,继续注册读事件 监听服务器端发送信息
             */
            client = (SocketChannel) selectionKey.channel();
            rBuffer.clear();
            count = client.read(rBuffer);
            if (count > 0) {
                receiveText = new String(rBuffer.array(), 0, count);
                System.out.println(receiveText);
                client = (SocketChannel) selectionKey.channel();
                client.register(selector, SelectionKey.OP_READ);
            }
        }
    }
}

server通道

package learn.nio;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.SocketAddress;
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.util.ArrayList;
import java.util.List;
import java.util.Set;

/*
 * 实现了nio连接,读写传输,通道关闭操作
 */
public class ServerSocketChannelDemo {

    public static boolean btemp = false;
    public static String stemp = "";
    public static Integer itemp = 0;
    public static Selector selector;
    // 装写入数据缓存,分配一个新的字节缓冲区
    public static ByteBuffer wbuffer = ByteBuffer.allocate(1024);
    // 装读入数据缓存,分配一个新的字节缓冲区
    public static ByteBuffer rbuffer = ByteBuffer.allocate(1024);
    // 装已连接的客户端
    public static List<SocketChannel> clients = new ArrayList<SocketChannel>();

    public static void dispose(SelectionKey key) throws IOException {
        ServerSocketChannel serverSocketChannel = null;
        SocketChannel socketChannel = null;
        btemp = key.isValid();
        if (btemp) {
            System.out.println("这事件是否有效: " + btemp);

            btemp = key.isReadable();
            if (btemp) {
                System.out.println("是否为读取key: " + btemp);
                // 获取注册该事件的通道
                socketChannel = (SocketChannel) key.channel();
                btemp = socketChannel.isConnected();
                System.out.println("是否连接成功: " + btemp);
                btemp = socketChannel.isConnectionPending();
                System.out.println("是否正在连接: " + btemp);
                btemp = socketChannel.isRegistered();
                System.out.println("是否注册到选择器: " + btemp);
                btemp = socketChannel.isOpen();
                System.out.println("是否打开通道: " + btemp);

                // 用之前选清空一下
                rbuffer.clear();
                itemp = socketChannel.read(rbuffer);
                // 读取的字节数,可能为零,如果该通道已到达流的末尾,则返回 -1 大于0表示有数据
                System.out.println("客户端转过来的字节长度: " + itemp);
                if (itemp > 0) {
                    // 反转缓存
                    rbuffer.flip();
                    stemp = new String(rbuffer.array());
                    System.out.println("读取内容: " + stemp);
                    // 转发给其他客户端
                    int count = 1;
                    for (SocketChannel client : clients) {
                        if (!client.equals(socketChannel)) {
                            btemp = client.isOpen();
                            System.out.println("客户端通道是否打开: " + btemp);
                            btemp = client.isConnected();
                            System.out.println("客户端通道连接是否成功: " + btemp);
                            btemp = client.socket().isClosed();
                            System.out.println("客户端socket是否关闭: " + btemp);
                            System.out.println("服务端存入的客户端数: " + clients.size());
                            if (client.isOpen() && client.isConnected()) {
                                System.out.println("转发 " + count + " 个客户端");
                                count++;
                                // 用之前选清空一下
                                wbuffer.clear();
                                wbuffer.put(stemp.getBytes());
                                // 装完数据,反转下
                                wbuffer.flip();
                                client.write(wbuffer);
                            }
                        }

                    }
                } else if (itemp == 0) {
                    System.out.println("无视");
                } else if (itemp < 0) {
                    System.out.println("客户端已关闭,关闭该通道");
                    socketChannel.close();
                    // 注销这无效读事件
                    // key.cancel();
                    System.out.println("退出函数");
                    return;
                }

            }
            btemp = key.isAcceptable();
            if (btemp) {
                System.out.println("是否接受新的套接字连接key: " + btemp);
                // 获取注册该事件的通道
                serverSocketChannel = (ServerSocketChannel) key.channel();
                // 接收连接,返回客户端通道
                socketChannel = serverSocketChannel.accept();

                // 将以连接的客户端连接保存起来
                clients.add(socketChannel);
                System.out.println("打印客户端socket地址" + socketChannel.getRemoteAddress());
                // System.out.println("处理完结束客户端这次请求是否成功: " + btemp);
                // System.exit(1);
                // 是否阻塞
                socketChannel.configureBlocking(false);
                // 将客户端注册读事件key到选择器上
                socketChannel.register(selector, SelectionKey.OP_READ);

            }
            btemp = key.isConnectable();
            if (btemp) {
                System.out.println("是否连接操作key: " + btemp);

            }
            btemp = key.isWritable();
            if (btemp) {
                System.out.println("是否写入key: " + btemp);
            }

        } else {
            System.out.println("有无效事件key");
        }

    }

    public static void listen() {
        while (true) {
            try {
                itemp = selector.select();
                if (itemp != 0) {
                    System.out.println("触发事件数: " + itemp);
                }
                Set<SelectionKey> keys = selector.selectedKeys();
                if (!keys.isEmpty()) {
                    System.out.println("事件key数: " + keys.size());
                    for (SelectionKey key : keys) {
                        dispose(key);
                    }
                    // 经过事件处理方法后清空
                    keys.clear();
                }

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

    public static void main(String[] args) {
        try {
            // 打开通道
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            btemp = serverSocketChannel.isOpen();
            System.out.println("通道是否打开: " + btemp);
            // io是否阻塞
            serverSocketChannel.configureBlocking(false);
            ServerSocket serverSocket = serverSocketChannel.socket();
            // 创建通道选择器
            selector = Selector.open();
            /*
             * 注册选择器 OP_ACCEPT 用于套接字接受操作的操作集位。 OP_CONNECT 用于套接字连接操作的操作集位 OP_READ
             * 用于读取操作的操作集位 OP_WRITE 用于写入操作的操作集位。
             * 
             */
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            btemp = serverSocketChannel.isRegistered();
            System.out.println("该通道是否有选择器注册: " + btemp);
            // 绑定ip和端口
            serverSocket.bind(new InetSocketAddress("localhost", 9999));

            // 如果Socket已经与一个本地端口绑定, 则返回true , 否则返回false
            btemp = serverSocket.isBound();
            System.out.println("如果Socket已经与一个本地端口绑定, 则返回true , 否则返回false: " + btemp);
            itemp = serverSocket.getLocalPort();
            System.out.println("获取ServerSocket的port,没设置则为-1: " + itemp);
            serverSocketChannel = serverSocket.getChannel();// 获取所属nio通道
            InetAddress iaddr = serverSocket.getInetAddress();
            // 没有设置地址则该对象为空
            if (iaddr == null) {
                System.out.println("iaddr==null");
            } else {
                stemp = iaddr.getHostAddress();
                System.out.println("ip地址: " + stemp);
                System.out.println("InetAddress实例toString" + iaddr.toString());
            }
            SocketAddress saddr = serverSocket.getLocalSocketAddress();
            if (saddr == null) {
                System.out.println("saddr==null");
            } else {
                System.out.println("SocketAddress对象打印: " + saddr);
            }

            /*
             * ReceiveBufferSize
             * TCP发送缓存区和接收缓存区,默认是8192,一般情况下足够了,而且就算你增加了发送缓存区,对方没有增加它对应的接收缓冲,
             * 那么在TCP三握手时,最后确定的最大发送窗口还是双方最小的那个缓冲区,就算你无视,发了更多的数据,那么多出来的数据也会被丢弃。
             * 除非双方都协商好。
             */
            itemp = serverSocket.getReceiveBufferSize();
            System.out.println("缓存区和接收缓存区默认是8192: " + itemp);
            btemp = serverSocket.getReuseAddress();
            System.out.println(btemp);
            itemp = serverSocket.getSoTimeout();
            System.out.println("serverSocket超时设置 默认0不会超时: " + itemp);
            listen();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

client通道

package learn.nio;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Set;

public class SocketChannelDemo {
    public static boolean btemp = false;
    public static String stemp = "";
    public static Integer itemp = 0;
    public static Selector selector = null;
    public static ByteBuffer wbuffer = ByteBuffer.allocate(1024);
    public static ByteBuffer rbuffer = ByteBuffer.allocate(1024);

    public static void dispose(SelectionKey key) throws IOException {
        SocketChannel socketChannel = null;

        btemp = key.isValid();
        if (btemp) {
            System.out.println("这事件key是否有效: " + btemp);
            btemp = key.isConnectable();
            if (btemp) {
                System.out.println("是否连接服务端成功: " + btemp);
                socketChannel = (SocketChannel) key.channel();
                // 确认连接建立完成,没有这个服务端会一直提示有个客户端有个连接请求没有处理
                btemp = socketChannel.finishConnect();
                System.out.println("对服务端表示客户端连接是否完成: " + btemp);
                System.out.println("连接服务端成功");
                if (btemp) {
                    // System.exit(1);
                    // System.out.println("退出");
                }
                // 给客户端发数据
                stemp = new Date() + "一个客户端连接服务端成功";
                // 用之前先清空一下
                wbuffer.clear();
                // 添加写内容
                wbuffer.put(stemp.getBytes());
                // 反转一下,不然服务端读不出来
                wbuffer.flip();
                // 通过通道客户端通道传给服务端
                socketChannel.write(wbuffer);
                // 注册读事件key
                socketChannel.register(selector, SelectionKey.OP_READ);

            }

            btemp = key.isReadable();
            if (btemp) {

                System.out.println("客户端处理读事件");
                socketChannel = (SocketChannel) key.channel();
                btemp = socketChannel.isOpen();
                System.out.println("客户端通道是否打开: " + btemp);
                btemp = socketChannel.isConnected();
                System.out.println("客户端通道是否连接成功: " + btemp);
                if (!socketChannel.isOpen() || !socketChannel.isConnected()) {
                    System.out.println("该通道以关闭");

                }
                // 用之前先清空一下
                rbuffer.clear();
                itemp = socketChannel.read(rbuffer);
                if (itemp > 0) {
                    // 装完数据反转一下
                    rbuffer.flip();
                    stemp = new String(rbuffer.array());
                    System.out.println("服务器传过来的消息" + stemp);
                    btemp = socketChannel.socket().isClosed();
                    System.out.println("客户端socket是否关闭: " + btemp);

                } else if (itemp == 0) {

                } else if (itemp < 0) {
                    System.out.println("服务端关闭了通道");
                    socketChannel.close();
                }

                if (socketChannel.isOpen()) {
                    // 接收服务端的消息退出
                    socketChannel.close();
                    // key.cancel();
                    System.out.println("客户端关闭通道,关闭客户端程序");
                    System.exit(1);
                }
            }
        } else {
            System.out.println("有无效事件key");
        }

    }

    public static void listen() throws IOException {
        while (true) {
            itemp = selector.select();
            if (itemp != 0) {
                System.out.println("客户端事件数: " + itemp);
                itemp = 0;
            }
            Set<SelectionKey> keys = selector.selectedKeys();
            if (!keys.isEmpty()) {
                System.out.println("事件key数: " + keys.size());
                for (SelectionKey key : keys) {
                    dispose(key);
                }
                // 经过事件处理方法后清空
                keys.clear();
            }

        }
    }

    public static void main(String[] args) throws IOException {
        SocketChannel socketChannel = SocketChannel.open();
        // 是否阻塞
        socketChannel.configureBlocking(false);
        selector = Selector.open();
        socketChannel.register(selector, SelectionKey.OP_CONNECT);
        // 绑定客户端网络地址,不绑定则随机分配
        // socketChannel.bind(new InetSocketAddress("localhost", 6666));
        // 连接服务端网络地址
        socketChannel.connect(new InetSocketAddress("localhost", 9999));

        // 返回相关socket
        Socket socket = socketChannel.socket();
        // 获取所属nio通道
        socket.getChannel();

        btemp = socket.getKeepAlive();
        System.out.println("是否为保留socket: " + btemp);
        InetAddress iaddr = socket.getLocalAddress();
        if (iaddr == null) {
            System.err.println("iaddr==null");
        } else {
            stemp = iaddr.getHostAddress();
            System.out.println("获取InetAddress实例hostAddress 默认 0.0.0.0: " + stemp);
            stemp = iaddr.getHostName();
            System.out.println("获取InetAddress实例hostName 默认 0.0.0.0: " + stemp);
        }
        itemp = socket.getLocalPort();
        System.out.println("socket端口,没设置为-1: " + itemp);
        SocketAddress socketAddress = socket.getRemoteSocketAddress();
        System.out.println("socketAddress实例打印没设置为null: " + socketAddress);
        itemp = socket.getSendBufferSize();
        System.out.println("tcp发送缓存区: " + itemp);
        itemp = socket.getReceiveBufferSize();
        System.out.println("tcp接收缓存区: " + itemp);
        btemp = socket.isBound();
        System.out.println("是否绑定网络地址" + btemp);
        btemp = socket.isClosed();
        System.out.println("是否以关闭" + btemp);
        btemp = socket.isConnected();
        System.out.println("是否在连接" + btemp);
        btemp = socket.isInputShutdown();
        System.out.println("是否关闭输入流" + btemp);
        btemp = socket.isOutputShutdown();
        System.out.println("是否关闭输出流" + btemp);
        listen();
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值