博客
关于我
JAVA-NIO实现聊天室详细代码说明
阅读量:301 次
发布时间:2019-03-01

本文共 7237 字,大约阅读时间需要 24 分钟。

服务端

github源码:https://github.com/JolyouLu/JAVAIO.git

src\main\java\com\JolyouLu\nio\groupchat 文件夹下

public class GroupChatServer {       //定义属性    private Selector selector;    private ServerSocketChannel listenChannel;    private static final int PORT = 6666;    //构造器 完成初始化工作    public GroupChatServer() {           try {               //得到选择器            selector = Selector.open();            //初始化ServerSocketChannel            listenChannel = ServerSocketChannel.open();            //绑定端口            listenChannel.socket().bind(new InetSocketAddress(PORT));            //设置非阻塞模式            listenChannel.configureBlocking(false);            //将来listenChannel注册到Selector            listenChannel.register(selector, SelectionKey.OP_ACCEPT);        }catch (IOException e){               e.printStackTrace();        }    }    //监听    public void listen(){           try {               //循环监听            while (true){                   int count = selector.select(2000); //阻塞2秒监听,通道有没有事件发生                if (count > 0){    //返回>0 有事件要处理                    //遍历selectedKeys集合                    Iterator
iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()){ //获取SelectionKey SelectionKey key = iterator.next(); if (key.isAcceptable()){ //如果通道发生,客户端连接事件 //为连接的客户端,生成socketChannel SocketChannel socketChannel = listenChannel.accept(); //切换非阻塞模式 socketChannel.configureBlocking(false); //把socketChannel注册到selector中,并监听读事件 socketChannel.register(selector,SelectionKey.OP_READ); //提示客户端连接上了 System.out.println(socketChannel.getRemoteAddress() + " 客户端 上线"); } if (key.isReadable()){ //如果通道发生,可读事件 //处理读 readData(key); } //清理读取的selectedKeys容器 防止重复处理 iterator.remove(); } } } }catch (Exception e){ e.printStackTrace(); }finally { } } //读取客户端消息 private void readData(SelectionKey key){ //定义一个SocketChannel SocketChannel channel = null; try { //取到关联的channel channel = (SocketChannel) key.channel(); //创建buffer ByteBuffer buffer = ByteBuffer.allocate(1024); int count = channel.read(buffer); //根据count的值做处理 if (count > 0){ //读取到数据 //把缓冲区的数据转字符串 String msg = new String(buffer.array(), "GBK"); //输出消息 System.out.println("from 客户端:"+ msg); //向其它客户端转发消息 sendInfoToOtherClients(msg,channel); } }catch (IOException e){ try { System.out.println(channel.getRemoteAddress() + " 离线了.."); //取消注册 key.cancel(); //关闭通道 channel.close(); } catch (IOException ioException) { ioException.printStackTrace(); } } } //转发消息给其它客户端(channel) private void sendInfoToOtherClients(String msg,SocketChannel self) throws IOException { System.out.println("服务器转发消息中..."); //遍历 所有的注册到Selector的SocketChannel排查self for (SelectionKey key : selector.keys()) { //取出通道 Channel targetChannel = key.channel(); //targetChanneld的类型是SocketChannel,并且targetChannel不是自己 if (targetChannel instanceof SocketChannel && targetChannel != self){ //转型 SocketChannel dest = (SocketChannel)targetChannel; //将来msg 存到buffer ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes("GBK")); //将来buffer的数据写入通道 dest.write(buffer); } } } public static void main(String[] args) { //初始化服务器对象 GroupChatServer chatServer = new GroupChatServer(); chatServer.listen(); }}

客户端

public class GroupChatClient {       //定义相关属性    private final String HOST = "127.0.0.1"; //服务器IP    private final int PORT = 6666; //服务器端口    private Selector selector;    private SocketChannel socketChannel;    private String username;    //构造器,初始化    public GroupChatClient() {           try {               //得到选择器            selector = Selector.open();            //连接服务            socketChannel = SocketChannel.open(new InetSocketAddress(HOST,PORT));            //设置非阻塞            socketChannel.configureBlocking(false);            //将来socketChannel注册到Selector,关注读事件            socketChannel.register(selector, SelectionKey.OP_READ);            //得到username            username = socketChannel.getLocalAddress().toString().substring(1);            System.out.println(username + " is ok ...");        }catch (Exception e){               e.printStackTrace();        }    }    //向服务器发送消息    public void sendInfo(String info){           info = username + " 说:" + info;        try {               socketChannel.write(ByteBuffer.wrap(info.getBytes("GBK")));        }catch (IOException e){               e.printStackTrace();        }    }    //读取从服务器端回复的消息    public void readInfo(){           try {               int readChannels = selector.select(2000);            if (readChannels > 0){   //有可用的通道                Iterator
iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()){ SelectionKey key = iterator.next(); if (key.isReadable()){ //得到相关的通道 SocketChannel socketChannel = (SocketChannel) key.channel(); //得到一个Buffer ByteBuffer buffer = ByteBuffer.allocate(1024); //buffer 读取通道数据 socketChannel.read(buffer); //把读到缓冲区的数据转成字符串 String msg = new String(buffer.array()); System.out.println(msg.trim()); } iterator.remove(); } } }catch (IOException e){ e.printStackTrace(); } } public static void main(String[] args) { //启动客户端 GroupChatClient chatClient = new GroupChatClient(); //启动一个线程,每隔开3秒读取服务器发送的数据 new Thread(new Runnable() { @Override public void run() { while (true){ chatClient.readInfo(); try { Thread.currentThread().sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); //发送数据 Scanner scanner = new Scanner(System.in); while (scanner.hasNextLine()){ String s = scanner.nextLine(); chatClient.sendInfo(s); } }}

测试

设置启动参数,当前类可以同时运行多个

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

转载地址:http://cyxo.baihongyu.com/

你可能感兴趣的文章
mysql 判断表字段是否存在,然后修改
查看>>
MySQL 到底能不能放到 Docker 里跑?
查看>>
mysql 前缀索引 命令_11 | Mysql怎么给字符串字段加索引?
查看>>
MySQL 加锁处理分析
查看>>
mysql 协议的退出命令包及解析
查看>>
mysql 参数 innodb_flush_log_at_trx_commit
查看>>
mysql 取表中分组之后最新一条数据 分组最新数据 分组取最新数据 分组数据 获取每个分类的最新数据
查看>>
MySQL 命令和内置函数
查看>>
mysql 四种存储引擎
查看>>
MySQL 在并发场景下的问题及解决思路
查看>>
MySQL 基础架构
查看>>
MySQL 基础模块的面试题总结
查看>>
MySQL 备份 Xtrabackup
查看>>
mYSQL 外键约束
查看>>
mysql 多个表关联查询查询时间长的问题
查看>>
mySQL 多个表求多个count
查看>>
mysql 多字段删除重复数据,保留最小id数据
查看>>
MySQL 多表联合查询:UNION 和 JOIN 分析
查看>>
MySQL 大数据量快速插入方法和语句优化
查看>>
mysql 如何给SQL添加索引
查看>>