Server:
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;
/**
* @author doubily
* 服务器 启动并监听端口
* 服务器 接收客户端信息,并实现转发[ 处理上线和和离线 ]
*/
public class GroupChatServer {
private Selector selector;
private ServerSocketChannel listenChannel;
private static final int PORT = 9527;
/**
* 初始化工作
*/
public GroupChatServer() {
try{
// 选择器
this. selector = Selector.open();
this.listenChannel = ServerSocketChannel.open();
// 监听端口
listenChannel.socket().bind(new InetSocketAddress(PORT));
// 设置非阻塞
listenChannel.configureBlocking(false);
// 注册到 selector
listenChannel.register(selector, SelectionKey.OP_ACCEPT);
}catch (IOException e) {
e.printStackTrace();
}
}
// 监听
public void listen() {
try {
// 循环处理
while(true) {
int count = selector.select(2000);
// 有事件处理
if (count > 0) {
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()){
// 取出 selectionKey
SelectionKey key = iterator.next();
// 监听到accept
if (key.isAcceptable()) {
SocketChannel sc = listenChannel.accept();
sc.configureBlocking(false);
// 将sc 注册到 selector
sc.register(selector, SelectionKey.OP_READ);
// 提示
System.out.println(sc.getRemoteAddress() + " 上线 ");
}
// 通道 发生 read 事件, 即通道是可读的状态
if (key.isReadable()) {
// 处理读
read(key);
}
// 当前 key 删除,避免重复处理
iterator.remove();
}
} else {
// System.out.println("等待中...");
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
}
}
/**
* 读取客户端消息
*/
private void read(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());
System.out.println("from 客户端:" + msg.trim());
// 向其他客户端转发消息(去掉自己)
send2Group(msg, channel);
}
}catch (IOException e) {
try {
System.out.println(channel.getRemoteAddress() + " 离线了");
// 取消注册
key.cancel();
// 关闭通道
channel.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
/**
* 转发消息给其他客户
*/
private void send2Group(String msg, SocketChannel self) throws IOException {
System.out.println("服务器转发消息中...");
// 遍历 所有注册到selector 上的 socketChannel,并排除 self
for (SelectionKey key: selector.keys()) {
// 通过 key 取出对应的 socketChannel
Channel targetChannel = key.channel();
// 排除自己
if (targetChannel instanceof SocketChannel && targetChannel != self) {
// 转型
SocketChannel dest = (SocketChannel) targetChannel;
// 将 msg 存储到 buffer
ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8));
// 将 buffer 的数据写入通道
dest.write(buffer);
}
}
}
public static void main(String[] args) {
// 创建服务器对象
GroupChatServer groupChatServer = new GroupChatServer();
groupChatServer.listen();
}
}
Client:
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.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Scanner;
/**
* @author doubily
* 发送消息
* 接收服务器信息
*/
public class GroupChatClient {
// 服务器IP
private final String HOST = "127.0.0.1";
// 服务器 端口
private final Integer PORT = 9527;
private Selector selector;
private SocketChannel socketChannel;
private String username;
// 构造器
public GroupChatClient() throws IOException {
selector = Selector.open();
socketChannel = SocketChannel.open(new InetSocketAddress(HOST, PORT));
// 设置非阻塞
socketChannel.configureBlocking(false);
// 将 channel 注册到 selector
socketChannel.register(selector, SelectionKey.OP_READ);
// 得到 username;
username = socketChannel.getLocalAddress().toString().substring(1);
System.out.println(username + " is ok ...");
}
/**
* 向服务器 发送消息
* @param msg 消息
*/
public void send(String msg) {
msg = username + " 说:" + msg;
try {
socketChannel.write(ByteBuffer.wrap(msg.getBytes(StandardCharsets.UTF_8)));
}catch (IOException e) {
e.printStackTrace();
}
}
/**
* 从服务器端 回复的消息
*/
public void read() {
try{
int readChannels = selector.select();
// 有可以用的通道
if (readChannels > 0) {
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while(iterator.hasNext()) {
SelectionKey key = iterator.next();
if (key.isReadable()) {
// 得到相关的通道
SocketChannel sc = (SocketChannel) key.channel();
sc.configureBlocking(false);
// 得到一个Buffer
ByteBuffer buffer = ByteBuffer.allocate(1024);
sc.read(buffer);
// 把读到的缓冲区数据转成字符串
String msg = new String(buffer.array());
System.out.println(msg.trim());
}
iterator.remove();
}
} else {
// System.out.println("没有可用的通道...");
}
}catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
// 启动客户端
GroupChatClient chatClient = new GroupChatClient();
// 启动一个线程
new Thread() {
@Override
public void run(){
while (true) {
chatClient.read();
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.send(s);
}
}
}
效果图: