package com.eiot.netty.handler;
import okio.Buffer;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
/**
* 群聊nio客服端
* @author laijiangfeng
* @date 2022/12/7 17:26
*/
public class NIOServer {
//选择器
private Selector selector;
//客服端通道
private ServerSocketChannel serverSocketChannel;
//初始化数据
public NIOServer() {
try{
//初始化选择器
selector=Selector.open();
//初始化ServerSocketChannel
serverSocketChannel=ServerSocketChannel.open();
//绑定端口6666
serverSocketChannel.socket().bind(new InetSocketAddress(6666));
//设置非阻塞
serverSocketChannel.configureBlocking(false);
//将serverSocketChannel注册到selector
serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
}catch (IOException e){
e.printStackTrace();
}
}
/**
* 监听事件发生
* @throws IOException
*/
public void listen() throws IOException {
while (true){
//判断是否有通道发送事件
int count = selector.select();
//大于0有事件发生
if(count>0){
//获取有事件发生的key
Iterator iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()){
SelectionKey key = iterator.next();
//连接事件
if(key.isAcceptable()){
SocketChannel channel= serverSocketChannel.accept();
//设置非阻塞
channel.configureBlocking(false);
//将channel注册到选择器,并且关注读事件
channel.register(selector,SelectionKey.OP_READ);
System.out.println(channel.getRemoteAddress()+"上线了");
}
//读事件
if(key.isReadable()){
SocketChannel channel=null;
try{
//用buffer读取channel的信息
channel= (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int c = channel.read(buffer);
//大于0代表有信息
if(c>0){
String msg= new String(buffer.array());
System.out.println();
//向所有客户端发送信息
for (SelectionKey k : selector.keys()) {
Channel sc = k.channel();
//不向自己发送
if (sc instanceof SocketChannel && sc != channel) {
SocketChannel s = (SocketChannel) sc;
ByteBuffer wrap = ByteBuffer.wrap((channel.getRemoteAddress()+"说:"+msg.trim()).getBytes());
System.out.println("发送数据"+msg.trim());
s.write(wrap);
}
}
}
}catch (IOException e){
//读发生异常,通道关闭
System.out.println(channel.getRemoteAddress()+"离线了");
assert channel != null;
key.cancel();
channel.close();
}
}
//移除key防止重复处理
iterator.remove();
}
}
//一直循环占用cpu高,休息3s可减少cpu消耗
try{
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
}
}
/**
* 主线程启动
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//开启监听
NIOServer server = new NIOServer();
server.listen();
}
}
package com.eiot.netty.handler;
import lombok.SneakyThrows;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Scanner;
/**
* 群聊nio客户端
* @author laijiangfeng
* @date 2022/12/8 11:11
*/
public class NIOClient {
//选择器
private Selector selector;
//客户端SocketChannel
private SocketChannel socketChannel;
//初始化连接
public NIOClient() {
try {
//选择器初始化
selector=Selector.open();
//连接服务端获取socketChannel
socketChannel=SocketChannel.open(new InetSocketAddress("127.0.0.1",6666));
//设置非阻塞
socketChannel.configureBlocking(false);
//socketChannel管道注册关注读事件
socketChannel.register(selector, SelectionKey.OP_READ);
//连接上提示成功
System.out.println("登录成功...");
}catch (Exception e){
e.printStackTrace();
}
}
public void read() throws IOException {
//判断是否有管道发送事件
int c = selector.select();
//大于0代表有事件发生
if(c>0){
//获取有事件发生的key
Iterator iterator = selector.selectedKeys().iterator();
//循环获取key
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
//如果是读事件
if (key.isReadable()) {
//将通道数据读取到buffer
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer);
//转成字符串打印
String msg = new String(buffer.array());
System.out.println(msg.trim());
}
//防止循环重复需要移除,不移除导致客户端收不到消息
iterator.remove();
}
}
//一直循环占用cpu高,休息1s可减少cpu消耗
try{
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 将消息写入管道
* @param info
* @throws IOException
*/
public void write(String info) throws IOException {
socketChannel.write(ByteBuffer.wrap(info.trim().getBytes()));
}
/**
* 主线程运行测试
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//创建一个客户端用一个线程一直循环读取数据
NIOClient client = new NIOClient();
new Thread(() -> {
while (true){
try {
client.read();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
//主线程输入消息,并且将消息写入通道
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()){
String line = scanner.nextLine();
client.write(line);
}
}
}