博客
关于我
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中like % %模糊查询
查看>>
MySql中mvcc学习记录
查看>>
mysql中null和空字符串的区别与问题!
查看>>
MySQL中ON DUPLICATE KEY UPDATE的介绍与使用、批量更新、存在即更新不存在则插入
查看>>
MYSQL中TINYINT的取值范围
查看>>
MySQL中UPDATE语句的神奇技巧,让你操作数据库如虎添翼!
查看>>
Mysql中varchar类型数字排序不对踩坑记录
查看>>
MySQL中一条SQL语句到底是如何执行的呢?
查看>>
MySQL中你必须知道的10件事,1.5万字!
查看>>
MySQL中使用IN()查询到底走不走索引?
查看>>
Mysql中使用存储过程插入decimal和时间数据递增的模拟数据
查看>>
MySql中关于geometry类型的数据_空的时候如何插入处理_需用null_空字符串插入会报错_Cannot get geometry object from dat---MySql工作笔记003
查看>>
mysql中出现Incorrect DECIMAL value: '0' for column '' at row -1错误解决方案
查看>>
mysql中出现Unit mysql.service could not be found 的解决方法
查看>>
mysql中出现update-alternatives: 错误: 候选项路径 /etc/mysql/mysql.cnf 不存在 dpkg: 处理软件包 mysql-server-8.0的解决方法(全)
查看>>
Mysql中各类锁的机制图文详细解析(全)
查看>>
MySQL中地理位置数据扩展geometry的使用心得
查看>>
Mysql中存储引擎简介、修改、查询、选择
查看>>
Mysql中存储过程、存储函数、自定义函数、变量、流程控制语句、光标/游标、定义条件和处理程序的使用示例
查看>>
mysql中实现rownum,对结果进行排序
查看>>