java简单聊天 网络编程

demo1(单线程简单通讯)io流

服务端 

public class Server {
    public static void main(String[] args) throws Exception {
        //5.创建ServerSocket、Socket、OutputStream、InputStream以及端口号并初始化
        ServerSocket serverSocket = null;
        boolean flag = true;
        Socket socket = null;
        OutputStream out = null;
        InputStream in = null;
        try {
            //6.开启服务器并接收客户端发送的数据
            serverSocket = new ServerSocket(8000);//创建服务器套接字
            System.out.println("服务器开启,等待连接...");
            socket = serverSocket.accept();//获得连接
            //接收客户端发送的内容
            in = socket.getInputStream();
            //7.使用输出流对象将信息返回给客户端
            out = socket.getOutputStream();
            System.out.println(socket.getInetAddress().getHostAddress() + "---连接成功");
            out.write("连接成功".getBytes());
            out.flush();
            while (flag) {
                byte[] b = new byte[1024];
                int len = in.read(b);
                System.out.println("client:" + new String(b, 0, len));
                //控制台输入
                Scanner src = new Scanner(System.in);
                String str = src.nextLine();
                out.write(str.getBytes());
                out.flush();
                if (str.equals("bye")) {
                    flag = false;
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //8.关闭流对象、ServerSocket对象以及Socket对象
            in.close();
            out.close();
            serverSocket.close();
            socket.close();
        }
    }
}

客户端

public class Client {
    public static void main(String[] args) throws Exception {
        //1.定义 Socket 对象、OutputStream 对象和一个 InputStream 对象并完成初始化
        Socket socket = null;
        OutputStream out = null;
        InputStream in = null;
        boolean flag = true;
        //定义服务器端的 IP 地址和端口号
        String serverIP = "127.0.0.1";//服务器端 IP 地址
        int port = 8000;//服务器端端口号
        try {
            //2.建立与服务器端的连接并将数据发送到服务器端
            socket = new Socket(serverIP, port);//建立连接
            out = socket.getOutputStream();//发送数据
            while (flag) {
                //3.从输入流中读出服务器的反馈信息并输出到控制台
                byte[] b = new byte[1024];
                in = socket.getInputStream();
                int len = in.read(b);
                String response = new String(b, 0, len);
                System.out.println("server:" + response);
                if ("bye".equals(response)) {
                    flag = false;
                    break;
                }
                //控制台输入
                Scanner src = new Scanner(System.in);
                String str = src.nextLine();
                out.write(str.getBytes());
                out.flush();

            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //4.关闭流及 Socket 对象
            in.close();
            out.close();
            socket.close();
        }
    }
}

demo1(单线程简单通讯)nio

服务端

public class NIOServer {
    // 用于存放客户端SocketChannel集合
    private static  Map<String, SocketChannel> clientMap = new HashMap();

    private  static ByteBuffer sBuffer = ByteBuffer.allocate(1024);

    // 通道管理器(Selector)
    private static Selector selector;

    public static void main(String[] args) throws IOException {
        // 创建通道管理器(Selector)
        selector = Selector.open();

        // 创建通道ServerSocketChannel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        // 将通道设置为非阻塞
        serverSocketChannel.configureBlocking(false);

        // 将ServerSocketChannel对应的ServerSocket绑定到指定端口(port)
        ServerSocket serverSocket = serverSocketChannel.socket();
        serverSocket.bind(new InetSocketAddress(8000));
        /**
         * 将通道(Channel)注册到通道管理器(Selector),并为该通道注册selectionKey.OP_ACCEPT事件
         * 注册该事件后,当事件到达的时候,selector.select()会返回,
         * 如果事件没有到达selector.select()会一直阻塞。
         */
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务已启动等待连接。。。");
        // 循环处理
        while (true) {
            // 当注册事件到达时,方法返回,否则该方法会一直阻塞
            selector.select();

            // 获取监听事件
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();

            // 迭代处理
            while (iterator.hasNext()) {
                // 获取事件
                SelectionKey key = iterator.next();
                // 移除事件,避免重复处理
                iterator.remove();

                // 检查是否是一个就绪的可以被接受的客户端请求连接
                if (key.isAcceptable()) {
                    handleAccept(key);
                } else if (key.isReadable()) {// 检查套接字是否已经准备好读数据
                    handleRead(key);
                }

            }


        }
    }

    /**
     * 处理客户端连接成功事件
     */
    private static void handleAccept(SelectionKey key) throws IOException {
        // 获取客户端连接通道
        ServerSocketChannel server = (ServerSocketChannel) key.channel();
        SocketChannel socketChannel = server.accept();
        socketChannel.configureBlocking(false);

        // 信息通过通道发送给客户端
        String msg = "连接成功!";
        socketChannel.write(ByteBuffer.wrap(msg.getBytes()));
        // 启动线程监听客户端输入
        new Thread() {
            @Override
            public void run() {
                while (true) {
                    try {
                        sBuffer.clear();
                        //控制台输入
                        Scanner src = new Scanner(System.in);
                        String str = src.nextLine();
//                        System.out.println(sendText);
                        sBuffer.put(Charset.forName("UTF-8").encode(str));
                        sBuffer.flip();
                        socketChannel.write(sBuffer);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
        clientMap.put(getClientName(socketChannel), socketChannel);
        // 给通道设置读事件,客户端监听到读事件后,进行读取操作
        socketChannel.register(selector, SelectionKey.OP_READ);
    }

    /**
     * 监听到读事件,读取客户端发送过来的消息
     */
    private static void handleRead(SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();
        // 从通道读取数据到缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(128);
        channel.read(buffer);

        // 输出客户端发送过来的消息
        byte[] data = buffer.array();
        String msg = new String(data).trim();
        System.out.println("client:" + channel.toString() + "   " + msg);
        //转发给其他客户端
//        dispatch(channel, msg);
    }
    /**
     * 转发消息给各个客户端
     */
    private static void dispatch(SocketChannel client, String info) throws IOException {
        if (!clientMap.isEmpty()) {
            for (Map.Entry<String, SocketChannel> entry : clientMap.entrySet()) {
                SocketChannel temp = entry.getValue();
                if (!client.equals(temp)) {
                    sBuffer.clear();
                    sBuffer.put(Charset.forName("UTF-8").encode(getClientName(client) + ":" + info));
                    sBuffer.flip();
                    temp.write(sBuffer);
                }
            }
        }
    }

    /**
     * 生成客户端名字
     */
    private static  String getClientName(SocketChannel client){
        Socket socket = client.socket();
        return "[" + socket.getInetAddress().toString().substring(1) + ":" + Integer.toHexString(client.hashCode()) + "]";
    }

}

客户端


public class NIOClient {
    // 通道管理器(Selector)
    private static Selector selector;
    private static Charset charset = Charset.forName("UTF-8");
 
    public static void main(String[] args) throws IOException {
        // 创建通道管理器(Selector)
        selector = Selector.open();
 
        // 创建通道SocketChannel
        SocketChannel channel = SocketChannel.open();
        // 将通道设置为非阻塞
        channel.configureBlocking(false);
 
        // 客户端连接服务器,其实方法执行并没有实现连接,需要在handleConnect方法中调channel.finishConnect()才能完成连接
        channel.connect(new InetSocketAddress("localhost", 8000));
 
        /**
         * 将通道(Channel)注册到通道管理器(Selector),并为该通道注册selectionKey.OP_CONNECT
         * 注册该事件后,当事件到达的时候,selector.select()会返回,
         * 如果事件没有到达selector.select()会一直阻塞。
         */
        channel.register(selector, SelectionKey.OP_CONNECT);
        // 循环处理
        while (true) {
            /*
             * 选择一组可以进行I/O操作的事件,放在selector中,客户端的该方法不会阻塞,
             * selector的wakeup方法被调用,方法返回,而对于客户端来说,通道一直是被选中的
             * 这里和服务端的方法不一样,查看api注释可以知道,当至少一个通道被选中时。
             */
            selector.select();
 
            // 获取监听事件
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
 
            // 迭代处理
            while (iterator.hasNext()) {
                // 获取事件
                SelectionKey key = iterator.next();
 
                // 移除事件,避免重复处理
                iterator.remove();
 
                // 检查是否是一个就绪的已经连接服务端成功事件
                if (key.isConnectable()) {
                    handleConnect(key);
                } else if (key.isReadable()) {// 检查套接字是否已经准备好读数据
                    handleRead(key);
                }
 
            }
        }
    }
 
    /**
     * 处理客户端连接服务端成功事件
     */
    private static void handleConnect(SelectionKey key) throws IOException {
        // 获取与服务端建立连接的通道
        SocketChannel channel = (SocketChannel) key.channel();
        if (channel.isConnectionPending()) {
            // channel.finishConnect()才能完成连接
            channel.finishConnect();
        }
 
        channel.configureBlocking(false);
        ByteBuffer sBuffer = ByteBuffer.allocate(1024);
        // 数据写入通道
        String msg = "Hello Server!";
        channel.write(ByteBuffer.wrap(msg.getBytes()));
        // 启动线程监听客户端输入
        new Thread() {
            @Override
            public void run() {
                while (true) {
                    try {
                        sBuffer.clear();
                        //控制台输入
                        Scanner src = new Scanner(System.in);
                        String str = src.nextLine();
//                        System.out.println(sendText);
                        sBuffer.put(charset.encode(str));
                        sBuffer.flip();
                        channel.write(sBuffer);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();

        // 通道注册到选择器,并且这个通道只对读事件感兴趣
        channel.register(selector, SelectionKey.OP_READ);

    }
 
    /**
     * 监听到读事件,读取客户端发送过来的消息
     */
    private static void handleRead(SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();
 
        // 从通道读取数据到缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(128);
        channel.read(buffer);
 
        // 输出服务端响应发送过来的消息
        byte[] data = buffer.array();
        String msg = new String(data).trim();
        System.out.println("server:" + msg);
    }
}

 

发布了18 篇原创文章 · 获赞 8 · 访问量 3万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 黑客帝国 设计师: 上身试试

分享到微信朋友圈

×

扫一扫,手机浏览