Java NIO实现聊天系统
作者:菜鸟程序猿进阶之路 发布时间:2023-08-08 08:35:36
标签:Java,NIO,聊天系统
使用Java的NIO写的一个小的聊天系统,供大家参考,具体内容如下
一、服务端
/**
* 群聊的服端
*
* @author :breakpoint/赵立刚
* @date : 2020/08/13
*/
public class GroupChatServer {
// 定义相关的属性
private Selector selector;
private ServerSocketChannel listenChannel;
private static final int port = 6667;
// 构造器
// 进行初始化的操作
public GroupChatServer() {
try {
// 获取选择器
selector = Selector.open();
// 获取到 listenChannel
listenChannel = ServerSocketChannel.open();
// 设定端口
listenChannel.bind(new InetSocketAddress(port));
// 设定非阻塞模式
listenChannel.configureBlocking(false);
// 将该 listenChannel 注册到 selector上 完成操作
listenChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务器启动了。。。。");
} catch (IOException e) {
}
}
// 监听的代码
public void listen() {
try {
// 循环处理
while (true) {
int count = selector.select(2000);
if (count > 0) {
// 有事件需要处理
// 遍历处理 得到selectionKeys集合
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> selectionKeyIterator = selectionKeys.iterator();
while (selectionKeyIterator.hasNext()) {
// 得到selectionKey
SelectionKey selectionKey = selectionKeyIterator.next();
// 监听到了 accept
if (selectionKey.isAcceptable()) {
// 获取到连接
SocketChannel sc = listenChannel.accept();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
// 提示上线
System.out.println(sc.getRemoteAddress() + ":上线啦。。。。");
}
if (selectionKey.isReadable()) {
// 读取事件 通道是可以读的状态 //专门写
readData(selectionKey);
}
// 移除当前的删除 防止重复处理操作
selectionKeyIterator.remove();
}
} else {
System.out.println("等待中。。。。。。");
}
}
} catch (Exception e) {
} finally {
}
}
// 读取客户端的消息
private void readData(SelectionKey selectionKey) {
// 获取 socketChannel
SocketChannel channel = null;
try {
channel = (SocketChannel) selectionKey.channel();
ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment();
int count = channel.read(byteBuffer);
// 分情况处理
if (count > 0) {
// 获取到数据专程
String msg = new String(byteBuffer.array(), 0, count);
byteBuffer.clear();
System.out.println(channel.getRemoteAddress() + "来自客户端" + msg);
// 向其他的客户端转发消息
sendInfoToOtherClients(msg, channel);
}
} catch (IOException e) {
// 如果发生异常 提示说明离线了
try {
System.out.println(channel.getRemoteAddress() + "离线了。。。。");
// 取消注册
selectionKey.cancel();
// 关闭通道
channel.close();
} catch (IOException e1) {
//e1.printStackTrace();
}
} finally {
}
}
// 转发消息给其他的客户端 去掉自己的客户端
private void sendInfoToOtherClients(String msg, SocketChannel self) throws IOException {
System.out.println("服务器转发消息。。。。。");
// 进行遍历操作
Set<SelectionKey> keys = selector.keys();
for (SelectionKey key : keys) {
// 取出来所有的
Channel targetChannel = key.channel();
// 排除自己
if (targetChannel instanceof SocketChannel && targetChannel != self) {
SocketChannel dest = (SocketChannel) targetChannel;
ByteBuffer byteBuffer = ByteBuffer.wrap(msg.getBytes());
// 发送数据
dest.write(byteBuffer);
}
}
}
public static void main(String[] args) {
GroupChatServer groupChatServer = new GroupChatServer();
groupChatServer.listen();
}
}
二、客户端代码
/**
* @author :breakpoint/赵立刚
* @date : 2020/08/13
*/
public class GroupChatClient {
// 定义相关属性
private final String HOST = "127.0.0.1"; //服务器地址
private final int port = 6667; // 服务器端口
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();
System.out.println("客户端专备好啦");
} catch (IOException e) {
}
}
public void sendInfo(String info) {
String msg = userName + "说:" + info;
try {
ByteBuffer wrap = ByteBuffer.wrap(msg.getBytes());
socketChannel.write(wrap);
} catch (IOException e) {
e.printStackTrace();
}
}
// 读取信息
public void readInfo() {
try {
int readChannel = selector.select(2000);
if (readChannel > 0) {
// 有可以用的通道
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey next = iterator.next();
if (next.isReadable()) {
SelectableChannel keyChannel = next.channel();
if (keyChannel instanceof SocketChannel) {
// 获取到我们的通道
SocketChannel channel = (SocketChannel) keyChannel;
ByteBuffer allocate = ByteBuffer.allocate(1024);
// 读取数据
int read = channel.read(allocate);
if (read > 0) {
// 输出我们的消息
System.out.println(new String(allocate.array(), 0, read));
}
}// end if
}
iterator.remove();
}
} else {
System.out.println("没有可用的通道");
}
} catch (IOException e) {
}
}
public static void main(String[] args) throws Exception {
// 启动客户端的操作
final GroupChatClient groupChatClient = new GroupChatClient();
// 启动一个线程
new Thread(() -> {
while (true) {
groupChatClient.readInfo();
try {
Thread.currentThread().sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
// 输入信息
String s = scanner.nextLine();
groupChatClient.sendInfo(s);
}
System.in.read();
}
}
三、运行的结果
来源:https://blog.csdn.net/zhaoligang1234/article/details/107988923
0
投稿
猜你喜欢
- Code CacheJVM生成的native code存放的内存空间称之为Code Cache;JIT编译、JNI等都会编译代码到nativ
- 什么是JPA一种规范,并非ORM框架,也就是ORM上统一的规范spring-boot-starter-data-jpa
- 摘要 &n
- 根据约定,在使用java编程的时候应尽可能的使用现有的类库,当然你也可以自己编写一个排序的方法,或者框架,但是有几个人能写得比JDK里的还要
- 前言Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其
- 本文讲述了Android自定义横向滑动菜单的实现。分享给大家供大家参考,具体如下:前言 开发安卓过程中,经常会用到标题栏的样式,有
- 本文实例讲述了JAVA设计模式之建造者模式定义与用法。分享给大家供大家参考,具体如下:建造者模式:将复杂对象的构造与它的实现相分离,让相同的
- 一、下载https://www.eclipse.org/downloads/download.php?file=/oomph/epp/202
- Spring Security的本质Spring Security 本质上是一连串的 Filter , 然后又以一个独立的 Filter 的
- 个人认为,提供params关键字以实现方法形参个数可变是C#语法的一大优点。在方法形参列表中,数组类型的参数前加params关键字,通常可以
- 泛型在继承方面的体现类A是类B的父类,G<A>和G<B>二者不具有子父类关系,二者是并列关系@Test &
- 目标:双向拖动的自定义View国际惯例先预览后实现我们要实现的就是一个段位样式的拖动条,用来做筛选条件用的,细心的朋友可能会发现微信设置里面
- 1、抓取一般内容需要三个类:WebRequest、WebResponse、StreamReader所需命名空间:System.Net、Sys
- 原生系统Android8.1上,WiFi上出现感叹号,此时WiFi可正常访问。原因这是Android 5.0引入的网络评估机制:就是当你连上
- 谈到 Java 的线程池最熟悉的莫过于 ExecutorService 接口了,jdk1.5 新增的 java.util.concurren
- 前言String 类在Java中是很常用的类,很重要的类,在后续的学习中经常会用到,是后续学习的基础一、认识String1.JDK中的Str
- 前言Feign是一个声明式的Web服务客户端,是面向接口编程的。也就是说使用Feign,只需要创建一个接口并使用注解方式配置它,就可以完成对
- 一、C#和JS互相调用 1、js调用C# C#代码如下: webView.CoreWebView2.AddHo
- 可能我们用惯了 Newtonsoft.Json.dll 等第三方的类库来实现序列化等类似的操作,但是有时只是简单的用一下,感觉没必要那么费事
- 目录前言一、技术介绍1.ReentranReadWriteLock是什么?二、源码分析1.ReadLock2.WriteLock三、单元测试