博客
关于我
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/

你可能感兴趣的文章
mysqldump 导出中文乱码
查看>>
mysqldump 导出数据库中每张表的前n条
查看>>
mysqldump: Got error: 1044: Access denied for user ‘xx’@’xx’ to database ‘xx’ when using LOCK TABLES
查看>>
Mysqldump参数大全(参数来源于mysql5.5.19源码)
查看>>
mysqldump备份时忽略某些表
查看>>
mysqldump实现数据备份及灾难恢复
查看>>
mysqldump数据库备份无法进行操作只能查询 --single-transaction
查看>>
mysqldump的一些用法
查看>>
mysqli
查看>>
MySQLIntegrityConstraintViolationException异常处理
查看>>
mysqlreport分析工具详解
查看>>
MySQLSyntaxErrorException: Unknown error 1146和SQLSyntaxErrorException: Unknown error 1146
查看>>
Mysql_Postgresql中_geometry数据操作_st_astext_GeomFromEWKT函数_在java中转换geometry的16进制数据---PostgreSQL工作笔记007
查看>>
mysql_real_connect 参数注意
查看>>
mysql_secure_installation初始化数据库报Access denied
查看>>
MySQL_西安11月销售昨日未上架的产品_20161212
查看>>
Mysql——深入浅出InnoDB底层原理
查看>>
MySQL“被动”性能优化汇总
查看>>
MySQL、HBase 和 Elasticsearch:特点与区别详解
查看>>
MySQL、Redis高频面试题汇总
查看>>