NIO编程之多客户端聊天系统
1. 服务端
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set; public class GroupChatServer {
private Selector selector;
private ServerSocketChannel listenChannel;
private static final int PORT = 8888; // 构造 器
public GroupChatServer() {
try {
selector = Selector.open();
listenChannel = ServerSocketChannel.open();
// 绑定端口
listenChannel.socket().bind(new InetSocketAddress(PORT));
// 设置非阻塞模式
listenChannel.configureBlocking(false);
// 将listenChannel注册到selector
listenChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (Exception e) {
e.printStackTrace();
}
} /**
* 监听
*/
public void listen() {
try {
while (true) {
//select(2000) 只阻塞2秒
// int count = selector.select(2000);
// select()方法一直阻塞
int count = selector.select();
if (count > 0) {
// 遍历得到所有的SelectionKey集合 Iterator<SelectionKey> keysIterator = selector.selectedKeys().iterator();
while (keysIterator.hasNext()) {
// 处理每个selectionKey
SelectionKey selectionKey = keysIterator.next();
// 监听到连接事件
if (selectionKey.isAcceptable()) {
SocketChannel socketChannel = listenChannel.accept();
socketChannel.configureBlocking(false);
//注册
socketChannel.register(selector, SelectionKey.OP_READ);
// 提示上线
System.out.println(socketChannel.getRemoteAddress() + "上线");
}
// 通道可读事件
if (selectionKey.isReadable()) {
// todo 处理读
readMessage(selectionKey);
}
// 删除key,防止重复处理
keysIterator.remove();
}
} else {
// System.out.println("等待中。。。。");
}
}
} catch (Exception e) {
e.printStackTrace();
} } /**
* 读取客户端消息
*
* @param key
*/
public void readMessage(SelectionKey key) {
SocketChannel socketChannel = null;
try {
socketChannel = (SocketChannel) key.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
int read = socketChannel.read(byteBuffer);
// 根据read值做处理,如果read > 0 说明真的读取到数据了
if (read > 0) {
String message = new String(byteBuffer.array());
System.out.println("Form Client : " + message);
// todo 向其它客户端 转发消息
sendInfoToOtherClient(message, socketChannel);
} } catch (IOException e) {
try {
System.out.println(socketChannel.getRemoteAddress() + "离线了。。。");
// 离线之后取消注册
key.cancel();
// 关闭channel
socketChannel.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
} /**
* 转发消息到其它客户端
*
* @param message 转发的消息
* @param self : 排除的channel
*/
public void sendInfoToOtherClient(String message, SocketChannel self) throws IOException {
System.out.println("服务器转发消息中。。。");
// 遍历所有注册到selector上的socketChannel,并排除自己
Set<SelectionKey> keys = selector.keys();
for (SelectionKey key : keys) {
// 通过key取出对应的SocketChannel
Channel targetChannel = key.channel();
// 排除自己
if (targetChannel instanceof SocketChannel && targetChannel != self) {
SocketChannel target = (SocketChannel) targetChannel;
// 将message 存储到buffer
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
// 将buffer中的数据写入通道
target.write(buffer);
} }
} public static void main(String[] args) {
//创建对象
GroupChatServer chatServer = new GroupChatServer();
chatServer.listen();
}
}
2. 客户端
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.SocketChannel;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set; public class GroupChatClient {
// 服务器ip
private final String HOST = "127.0.0.1";
// 服务器端口
private final int PORT = 8888;
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.register(selector, SelectionKey.OP_READ);
username = socketChannel.getLocalAddress().toString().substring(1);
System.out.println(username + " ok!");
} catch (Exception e) {
e.printStackTrace();
}
} /**
* 向服务端发送消息
*
* @param info 消息内容
*/
public void sendInfo(String info) {
info = username + "说:" + info;
try {
socketChannel.write(ByteBuffer.wrap(info.getBytes()));
} catch (IOException e) {
e.printStackTrace();
}
} /**
* 从服务端 读取消息
*/
public void readInfo() {
try {
int readChannels = selector.select(2000);
if (readChannels > 0) {
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> keyInterator = keys.iterator(); while (keyInterator.hasNext()) {
SelectionKey selectionKey = keyInterator.next();
if (selectionKey.isReadable()) {
// 得到读相关通道
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
socketChannel.read(byteBuffer);
//把buffer中的数据转成字符 串
String messge = new String(byteBuffer.array());
System.out.println( messge.trim());
}
//删除当前selectionKey
keyInterator.remove();
} } else {
// System.out.println("没有可用通道。。。。") }
} catch (IOException e) {
e.printStackTrace();
}
} public static void main(String[] args) {
// 启动客户端
GroupChatClient chatClient = new GroupChatClient(); // 启动一个线程每隔2秒读取从服务端发送过来的数据
new Thread() {
@Override
public void run() {
while (true) {
chatClient.readInfo();
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start(); // 发送数据到服务端
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
String info = scanner.next();
chatClient.sendInfo(info);
} }
}
NIO编程之多客户端聊天系统的更多相关文章
- JDK NIO编程
我们首先需要澄清一个概念:NIO到底是什么的简称?有人称之为New I/O,因为它相对于之前的I/O类库是新增的,所以被称为New I/O,这是它的官方叫法.但是,由于之前老的I/O类库是阻塞I/O, ...
- Reactor 典型的 NIO 编程模型
Doug Lea 在 Scalable IO in Java 的 PPT 中描述了 Reactor 编程模型的思想,大部分 NIO 框架和一些中间件的 NIO 编程都与它一样或是它的变体.本文结合 P ...
- Java IO编程全解(四)——NIO编程
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7793964.html 前面讲到:Java IO编程全解(三)——伪异步IO编程 NIO,即New I/O,这 ...
- NIO和IO(BIO)的区别及NIO编程介绍
IO(BIO)和NIO的区别:其本质就是阻塞和非阻塞的区别. 阻塞概念:应用程序在获取网络数据的时候,如果网络传输数据很慢,那么程序就一直等着,直到传输完毕为止. 非阻塞概念:应用程序直接可以获取已经 ...
- Nio编程模型总结
终于,这两天的考试熬过去了, 兴致冲冲的来整理笔记来, 这篇博客是我近几天的NIO印象笔记汇总,记录了对Selector及Selector的重要参数的理解,对Channel的理解,常见的Channel ...
- NIO 编程模型
NIO 编程模型 Doug Lea 在 Scalable IO in Java 的 PPT 中描述了 Reactor 编程模型的思想,大部分 NIO 框架和一些中间件的 NIO 编程都与它一样或是它的 ...
- 手动搭建I/O网络通信框架3:NIO编程模型,升级改造聊天室
第一章:手动搭建I/O网络通信框架1:Socket和ServerSocket入门实战,实现单聊 第二章:手动搭建I/O网络通信框架2:BIO编程模型实现群聊 在第二章中用BIO编程模型,简单的实现了一 ...
- 深入学习Netty(2)——传统NIO编程
前言 学习Netty编程,避免不了从了解Java 的NIO编程开始,这样才能通过比较让我们对Netty有更深的了解,才能知道Netty大大的好处.传统的NIO编程code起来比较麻烦,甚至有遗留Bug ...
- 循序渐进Socket网络编程(多客户端、信息共享、文件传输)
循序渐进Socket网络编程(多客户端.信息共享.文件传输) 前言:在最近一个即将结束的项目中使用到了Socket编程,用于调用另一系统进行处理并返回数据.故把Socket的基础知识总结梳理一遍. 1 ...
随机推荐
- 织梦dedecms发布视频文章前台变成一张图片的解决方法
在发布文章的时候,有时需要插入视频的代码,如优酷.腾讯等视频,这样更能让文章变的丰富,但是在发布视频的时候,前台并不能播放视频,而是一张图片 解决这个方法其实很简单,在发布视频文章的时候,将附加选项的 ...
- python2.7+appium环境搭建
实现android自动化 目录 1.环境准备.安装包准备 2.安装 3.验证环境搭建成功 1.环境准备.安装包准备 第一步:环境准备: java环境 python环境 第二步:准备安装包 Node.j ...
- UI自动化之三种等待
UI自动化中常用三种等待 目录 1.强制等待 2.隐式等待 3.显示等待 1.强制等待 执行到某一条语句后,然后sleep(3),等待3秒后,才会继续执行后面的语句 2.隐式等待 隐式等待只需要声明一 ...
- Jmeter+ SeureCRT + Pinpoint
1.环境配置 [相关操作] 下载jdk http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.h ...
- 第一章:Java语言概述与环境开发
1.计算机高级语言按程序的执行方式可以分为编译型和解释型两种: 2.JAVA程序的执行过程必须经过先编译后解释两个步骤: 3.JAVA语言里负责执行字节码文件的是JAVA虚拟机 (Java Virtu ...
- 浅谈vue单页面seo问题
最近做项目的时候,被要求做seo,由于项目已经开发完毕,且只需首页做seo,所以考虑再三,决定用prerender-spa-plugin结合vue-meta-info来实现首页的seo.如果你的页面是 ...
- Win10.更新
1.资料: win10怎么关闭自动更新?win10关闭自动更新步骤-太平洋IT百科.html(https://product.pconline.com.cn/itbk/software/win10/1 ...
- python基础-7.2文件内置属性__doc__ __file__ __package__ __cached__ __name__
__doc__ #py文件开头的注释文字 __file__ #当前py文件的路径 __package__ #包含文件所在包,用 . 分隔,当前文件为None,导入的其他文件:指定文件所在包,用.分隔. ...
- Linked List Cycle(链表成环)
判断链表中是否有环 来源:https://leetcode.com/problems/linked-list-cycle Given a linked list, determine if it ha ...
- [Web 前端] 015 css 三种元素的介绍
1. 块元素,内联元素,内联块元素 元素就是标签 布局中常用的有三种标签 块元素 内联元素 内联块元素 1.1 块元素 也称为行元素 布局中常用的标签,如 div.p.ul.li.h1~h6.dl.d ...