千家信息网

Java NIO怎么实现聊天室功能

发表于:2024-12-02 作者:千家信息网编辑
千家信息网最后更新 2024年12月02日,这篇文章主要介绍了Java NIO怎么实现聊天室功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。具体内容如下代码里面已经包含了必要的
千家信息网最后更新 2024年12月02日Java NIO怎么实现聊天室功能

这篇文章主要介绍了Java NIO怎么实现聊天室功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

具体内容如下

代码里面已经包含了必要的注释,这里不详述了。实现了基本的聊天室功能。

常量类:

public class Constant {    public static final int serverPort = 44444;}

服务端:

package server; import java.io.IOException;import java.net.InetSocketAddress;import java.net.SocketAddress;import java.nio.ByteBuffer;import java.nio.channels.ClosedChannelException;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.Iterator;import java.util.Set; import constant.Constant; public class SocketServer {    private Charset charset = Charset.forName("UTF-8");    private ServerSocketChannel serverSocketChannel;    private Selector serverSocketSelector;    private SelectionKey serverRegisterKey;    private ByteBuffer buffer = ByteBuffer.allocate(1024);     public static void main(String[] args) throws IOException {        new SocketServer().openServer(new InetSocketAddress(Constant.serverPort));    }     public void openServer(SocketAddress address) throws IOException {        init(address);        handle();    }     private void init(SocketAddress address) throws IOException {        serverSocketSelector = Selector.open();         serverSocketChannel = ServerSocketChannel.open();        serverSocketChannel.configureBlocking(false);        serverRegisterKey = serverSocketChannel.register(serverSocketSelector, SelectionKey.OP_ACCEPT);         serverSocketChannel.socket().bind(address);    }     private void handle() throws IOException {        System.out.println("服务端open");        while (serverSocketSelector.select() > 0) {            Iterator iterator = serverSocketSelector.selectedKeys().iterator();             // 为什么这里要用迭代器,而不用增强for循环之类的呢?是因为这里获得一个key之后,要对其进行移除,避免二次处理,造成影响            while (iterator.hasNext()) {                dispatch(iterator.next());                iterator.remove();            }        }    }     private void dispatch(SelectionKey key) throws IOException {        if (key.isAcceptable()) {            accept(key);        } else if (key.isReadable()) {            readMessage(key);        } else if (key.isValid() && key.isWritable()) {            writeMessage(key);        }    }     private void accept(SelectionKey key) throws IOException, ClosedChannelException {        // 主要的是,接收事件是发生在服务器这边的,所以这边的通道要强转为ServerSocketChannel        ServerSocketChannel server = (ServerSocketChannel) key.channel();        SocketChannel client = server.accept();        client.configureBlocking(false);        // 同时再给该通道注册选择器,监听的内容的读取        client.register(serverSocketSelector, SelectionKey.OP_READ);    }     private void readMessage(SelectionKey key) throws IOException {        SocketChannel client = (SocketChannel) key.channel();        client.read(buffer);        // 调整为读取模式        buffer.flip();        String content = charset.decode(buffer).toString();        // 压缩空间,即抛弃已经读取的内容(实际上还在里面,只是处于等待被覆盖状态)        buffer.compact();        // 这里可以根据业务逻辑,设置不设置都可以,但是这里想接受到消息后立马回复一条消息,所以设置下一次感兴趣的(监听)事件为写        key.interestOps(SelectionKey.OP_WRITE);        // 设置系统回复信息        key.attach("系统已经收到你的消息\n");        // 开始广播这个客户端的内容到其他客户端        broadcast(key, content);    }     private void broadcast(SelectionKey self, String content) throws IOException {        Set selectedKeys = self.selector().keys();        for (SelectionKey key : selectedKeys) {             // 不能发送给自己,也不要服务器自己本身对这个有反应            if (key != self && key != serverRegisterKey) {                String oldMessage = (String) key.attach(null);                // 如果有旧消息的话,在下一次发送时,连同旧消息一起发送                key.attach(oldMessage != null ? oldMessage + content : content);                key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);            }        }    }     private void writeMessage(SelectionKey key) throws IOException {        SocketChannel client = (SocketChannel) key.channel();        // 获取发给这个客户端的消息,并清空消息        client.write(charset.encode((String) key.attach(null)));        key.interestOps(SelectionKey.OP_READ);    }}

客户端(包含了Socket版本和SocketChannel版本):

package client; import java.io.IOException;import java.net.InetSocketAddress;import java.net.Socket;import java.net.UnknownHostException;import java.nio.ByteBuffer;import java.nio.channels.SocketChannel;import java.nio.charset.Charset;import java.util.Scanner; import constant.Constant; public class SocketClient {     public static void main(String[] args) throws IOException {        nioVersion();        // ioVersion();    }     private static void ioVersion() throws UnknownHostException, IOException {        System.out.println("客户端");        final Socket socket = new Socket();        socket.connect(new InetSocketAddress(Constant.serverPort));         new Thread() {            @Override            public void run() {                Scanner scanner = new Scanner(System.in);                 while (scanner.hasNext()) {                    String line = scanner.nextLine();                    try {                        socket.getOutputStream().write((line + "\n").getBytes("UTF-8"));                    } catch (IOException e) {                        e.printStackTrace();                    }                }                scanner.close();                try {                    socket.close();                } catch (IOException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            };        }.start();         new Thread() {            @Override            public void run() {                try {                    Scanner scanner = new Scanner(socket.getInputStream(), "utf-8");                    while (scanner.hasNext()) {                        String line = scanner.nextLine();                        System.out.println("收到消息:" + line);                    }                    scanner.close();                } catch (IOException e) {                    e.printStackTrace();                }             }        }.start();    }     private static void nioVersion() throws IOException {        Charset charset = Charset.forName("UTF-8");         System.out.println("客户端");        SocketChannel socketChannel = SocketChannel.open();        // 设置为非阻塞模式        socketChannel.configureBlocking(false);        socketChannel.connect(new InetSocketAddress(Constant.serverPort));         while (true) {            if (socketChannel.finishConnect()) {                new Thread() {                    @Override                    public void run() {                        Scanner scanner = new Scanner(System.in);                        while (scanner.hasNext()) {                            String input = scanner.nextLine();                             try {                                socketChannel.write(charset.encode(input));                            } catch (IOException e) {                                e.printStackTrace();                            }                         }                        scanner.close();                    }                }.start();                 new Thread() {                    ByteBuffer dst = ByteBuffer.allocate(1024);                     @Override                    public void run() {                        while (true) {                            try {                                int len = socketChannel.read(dst);                                if (len > 0) {                                    dst.flip();                                    System.out.println("收到消息:" + charset.decode(dst));                                    dst.compact();                                }                            } catch (IOException e) {                                // TODO Auto-generated catch block                                e.printStackTrace();                            }                        }                    }                }.start();                return;            }        }    } }

感谢你能够认真阅读完这篇文章,希望小编分享的"Java NIO怎么实现聊天室功能"这篇文章对大家有帮助,同时也希望大家多多支持,关注行业资讯频道,更多相关知识等着你来学习!

0