GroupChatServer
package com.guiguixia.nio.groupchat;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
/**
* 群聊系统服务端
* @author wzcstart
* @date 2021/6/16 - 23:07
*/
public class groupChatServer {
//Selector - 选择器
private Selector selector;
//ServerSocketChannel - 服务端监听器
private ServerSocketChannel listenChannel;
//端口号
private final int PORT = 6667;
public groupChatServer() {
try {
//构造选择器
selector = Selector.open();
//构造服务端
listenChannel = ServerSocketChannel.open();
//绑定端口
listenChannel.socket().bind(new InetSocketAddress(PORT));
//设置非阻塞
listenChannel.configureBlocking(false);
//注册服务器监听器
listenChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务器准备好了");
}catch (IOException e){
e.printStackTrace();
}
}
//监听方法
public void listen(){
try {
while (true){
//监听
int count = selector.select();
//判断时候有触发事件
if (count > 0){
//获取触发的selectKey
Set<SelectionKey> selectionKeys = selector.selectedKeys();
//使用迭代器模式
Iterator<SelectionKey> skIterator = selectionKeys.iterator();
while (skIterator.hasNext()){
//获取当前的selectionKey
SelectionKey selectionKey = skIterator.next();
//处理连接事件
if (selectionKey.isAcceptable()){
//接受连接 - 本身此方法为阻塞但是已经发生了连接事件所以将直接获取channel
SocketChannel socketChannel = listenChannel.accept();
//设置为非阻塞
socketChannel.configureBlocking(false);
//注册此socketChannel
socketChannel.register(selector,SelectionKey.OP_READ);
System.out.println(socketChannel.getRemoteAddress() + "上线了");
}
//处理读事件
if (selectionKey.isReadable()){
//触发读事件
readData(selectionKey);
}
//移除已经处理过的selectionKey - 防止重复触发
skIterator.remove();
}
}else {
System.out.println("服务器无响应2s...");
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
}
}
//读取数据
private void readData(SelectionKey sk){
SocketChannel channel = null;
try {
//通过selectionKey获取通道
channel = (SocketChannel) sk.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
//读取
int count = channel.read(byteBuffer);
if (count>0){
String msg = new String(byteBuffer.array()).trim();
System.out.println("from 客户端:"+msg);
//转发消息
sendInfoToOther(msg,channel);
}
//转发 - 向其他channel转发消息
}catch (IOException e){
try {
//取消注册
sk.cancel();
//提示下线
System.out.println("客户端下线"+channel.getRemoteAddress());
//关闭资源
channel.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
sk.cancel();
}
}
//向其他channel转发消息
private void sendInfoToOther(String info,SocketChannel self) throws IOException{
System.out.println("服务器转发消息中...");
for(SelectionKey sk : selector.keys()){
SelectableChannel targetChannel = sk.channel();
if (targetChannel instanceof SocketChannel && targetChannel!=self){
//得到要转发的目标通道
SocketChannel dest = (SocketChannel) targetChannel;
//构建Buffer
ByteBuffer byteBuffer = ByteBuffer.wrap(info.getBytes());
//写入到目标通道
dest.write(byteBuffer);
}
}
}
public static void main(String[] args){
//创建服务器
groupChatServer groupChatServer = new groupChatServer();
groupChatServer.listen();
}
}
GroupChatClient
package com.guiguixia.nio.groupchat;
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.concurrent.TimeUnit;
/**
* 群聊客户端
*
* @author wzcstart
* @date 2021/6/17 - 23:10
*/
public class groupChatClient {
//服务端ip
private final String HOST = "127.0.0.1";
//服务端端口号
private final int PORT = 6667;
//客户端通道
private SocketChannel socketChannel;
//选择器
private Selector selector;
//此客户端名字 - 本地地址
private String username;
//构造初始化
public groupChatClient() {
try {
//构建选择器
selector = Selector.open();
//构建socketChannel
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 + " is ok...");
} catch (IOException e) {
e.printStackTrace();
}
}
//读服务器转发的消息
public void readInfo() {
try {
//监听事件的发生
int count = selector.select();
if (count > 0) {
//获取触发事件的迭代器
Iterator<SelectionKey> skIterator = selector.selectedKeys().iterator();
while (skIterator.hasNext()) {
SelectionKey sk = skIterator.next();
//判断是否是读事件被触发
if (sk.isReadable()) {
//获取通道
SocketChannel sc = (SocketChannel) sk.channel();
//获取消息
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
sc.read(byteBuffer);
String msg = new String(byteBuffer.array()).trim();
System.out.println(msg);
}
//移除当前触发事件 - 避免重复触发
skIterator.remove();
}
} else {
System.out.println("没有可用通道...");
}
} catch (IOException e) {
e.printStackTrace();
}
}
//发送给服务器消息
public void writeInfo(String info) {
info = username + " 说:" + info;
try {
socketChannel.write(ByteBuffer.wrap(info.getBytes()));
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
groupChatClient groupChatClient = new groupChatClient();
new Thread(() -> {
while (true) {
groupChatClient.readInfo();
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()){
String msg = scanner.nextLine();
groupChatClient.writeInfo(msg);
}
}
}