基于 java nio 长连接实现的聊天室

来源:互联网 发布:阿里云ecs ip 编辑:程序博客网 时间:2024/05/20 20:18

TCP长连接与短连接的区别

基于 java nio 长连接实现的聊天室,如果并发量大的话,可能会有线程问题。

服务端代码

package com.lp.io.socket;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.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.util.ArrayList;import java.util.Collections;import java.util.Iterator;import java.util.List;public class LpNioServerSocket {    //线程安全    private static List<SocketChannel> channels = Collections.synchronizedList( new ArrayList<SocketChannel>() );    public static void main(String[] args) {        HandlerSelectionKey handler = new HandlerHandlerSelectionKeyImpl();        try {            //创建 ServerSocketChannel            ServerSocketChannel server = ServerSocketChannel.open();            server.configureBlocking(false);            server.bind(new InetSocketAddress("localhost", 12345));            //创建 Selector            Selector selector = Selector.open();            server.register(selector, SelectionKey.OP_ACCEPT);            //死循环,持续接收 客户端连接            while(true) {                //selector.select(); 是阻塞方法                int keys = selector.select();                if(keys > 0) {                    Iterator<SelectionKey> it = selector.selectedKeys().iterator();                    while(it.hasNext()) {                        SelectionKey key = it.next();                        it.remove();                        //处理 SelectionKey                        handler.handler(key, selector);                    }                }            }        } catch (IOException e) {            e.printStackTrace();        }    }    /**     * SelectionKey 处理接口     *     */    public static interface HandlerSelectionKey {        public void handler(SelectionKey key, Selector selector) throws IOException;    }    /**     * SelectionKey 接口 实现类     *     */    public static class HandlerHandlerSelectionKeyImpl implements HandlerSelectionKey {        @Override        public void handler(SelectionKey key, Selector selector) throws IOException {            int keyState = selectionKeyState(key);            switch (keyState) {            case SelectionKey.OP_ACCEPT:                ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();                accept(serverSocketChannel, selector);                break;            case SelectionKey.OP_READ:                SocketChannel readSocketChannel = (SocketChannel) key.channel();                read(readSocketChannel, selector);                break;            }        }        /**         * 获取 SelectionKey 是什么事件         * @param key         * @return         */        private int selectionKeyState(SelectionKey key) {            if(key.isAcceptable()) {                return SelectionKey.OP_ACCEPT;            } else if(key.isReadable()) {                return SelectionKey.OP_READ;            }            return -1;        }        /**         * 接口客户端请求         * @param serverSocketChannel         * @param selector         * @throws IOException         */        private void accept(ServerSocketChannel serverSocketChannel, Selector selector) throws IOException {            SocketChannel socketChannel = serverSocketChannel.accept();            socketChannel.configureBlocking(false);            channels.add(socketChannel);            //将 channel 注册到  Selector            socketChannel.register(selector, SelectionKey.OP_READ);        }        /**         * 读取客户端发送过来的信息         * @param socketChannel         * @param selector         * @throws IOException         */        private void read(SocketChannel socketChannel, Selector selector) throws IOException {            ByteBuffer readBuffer = ByteBuffer.allocate(8192);            int readBytes = socketChannel.read(readBuffer);            String msg = "";//客户端发送来的消息            if(readBytes > 0) {                 msg = new String(readBuffer.array(), 0, readBytes);                System.out.println("客户端发送来的消息");                System.out.println(msg);            }            write(socketChannel, msg);        }        /**         * 响应客户端请求         * @param socketChannel         * @param selector         * @throws IOException         */        private void write(SocketChannel socketChannel, String msg) throws IOException {            msg = "游客" + socketChannel.hashCode()+ "\r\n    " + msg;            //响应消息            byte[] responseByte = msg.getBytes();            ByteBuffer writeBuffer = ByteBuffer.allocate(responseByte.length);            writeBuffer.put(responseByte);            writeBuffer.flip();            //响应客户端            for(int i=0; i<channels.size(); i++) {                if(!socketChannel.equals(channels.get(i))) {                    channels.get(i).write(writeBuffer);                }            }        }    }}

客户端代码

package com.lp.io.socket;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.net.Socket;import java.net.UnknownHostException;public class LpSocketClient1 {    /**     * @param args     * @throws IOException      * @throws UnknownHostException      * @throws InterruptedException      */    public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException {        final Socket socket = new Socket("localhost", 12345);        Thread inT = new Thread(new Runnable() {            @Override            public void run() {                try {                    while(true) {                        InputStream inputStream = socket.getInputStream();                        byte[] b = new byte[8192];                        int readSize = inputStream.read(b);                        System.out.println(new String(b,0,readSize));                    }                } catch (IOException e) {                    e.printStackTrace();                }            }        });        inT.start();        while(true) {            InputStreamReader stdin = new InputStreamReader(System.in);//键盘输入             BufferedReader bufin = new BufferedReader(stdin);             String str = bufin.readLine();             System.out.println(str);            OutputStream outStream = socket.getOutputStream();            outStream.write(str.getBytes());            outStream.flush();        }    }}

启动服务端代码,然后启动多个客户端。在某个客户端代码控制台输入英文(输入中文乱码),点击回车,可以看到其他客户端控制台有信息输出。

0 0
原创粉丝点击