服务器(selector实现):
package com.ronghao.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
public class GroupChatServer {
//定义属性
private Selector selector;
private ServerSocketChannel listenChannel;
private static final int PORT = 9999;
//初始化工作
public GroupChatServer() {
try {
//选择器
selector = Selector.open();
//通道
listenChannel = ServerSocketChannel.open();
listenChannel.socket().bind(new InetSocketAddress(PORT));
listenChannel.configureBlocking(false);
listenChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (IOException e) {
e.printStackTrace();
}
}
//监听
public void listen() {
try {
//循环处理
while (true) {
int count = selector.select();
if (count > 0) {//有事件处理
//遍历得到selectionKey集合
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() + "上线");
}
if (key.isReadable()) {//通道发送read事件,即通道是可读的状态
//处理读
readData(key);
}
//当前key从集合中删除,防止重复处理。
iterator.remove();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
//读取客户端消息
private void readData(SelectionKey key) {
//定义一个SocketChannel
SocketChannel channel = null;
try {
channel = channel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int count = channel.read(buffer);
if (count > 0) {
//把缓冲区的数据转换成字符串
String message = new String(buffer.array());
//输出该消息
System.out.println("from 客户端:" + message);
//向其他客户端转发消息(去掉自己),专门写一个方法来处理
sendInfoToOtherClients(message, channel);
}
} catch (IOException e) {
try {
System.out.println(channel.getRemoteAddress() + " 离线了");
//取消注册
key.cancel();
//关闭通道
channel.close();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
}
//转发消息给其它客户(通道)
private void sendInfoToOtherClients(String msg, SocketChannel self) throws IOException {
//遍历所有注册到selector上的SocketChannel,并排除self
for (SelectionKey key : selector.keys()) {
//通过key取出对应的SocketChannel
SelectableChannel targetChannel = key.channel();
//排除自己
if (targetChannel instanceof SocketChannel && targetChannel != self) {
//转型
SocketChannel dest = (SocketChannel) targetChannel;
//将msg存储到buffer
ByteBuffer buffer = ByteBuffer.wrap(msg.getBytes());
//将buffer的数据写入通道;
dest.write(buffer);
}
}
}
public static void main(String[] args) {
GroupChatServer server = new GroupChatServer();
server.listen();
}
}
客户端:
package com.ronghao.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Scanner;
public class GroupChatClient {
//定义相关属性
private final String HOST = "127.0.0.1";//服务器的ip
private final int PORT = 9999;//服务器端口
private SocketChannel socketChannel;
private String username;
//初始化工作
GroupChatClient() {
try {
//连接服务器
socketChannel = SocketChannel.open(new InetSocketAddress(HOST, PORT));
//非阻塞
username = socketChannel.getLocalAddress().toString().substring(1);
System.out.println(username + " is ok ...");
} catch (IOException e) {
e.printStackTrace();
}
}
//发送数据
public void sendInfo(String info) {
try {
info = username + " 说:" + info;
socketChannel.write(ByteBuffer.wrap(info.getBytes()));
} catch (IOException e) {
e.printStackTrace();
}
}
//读取从服务端回复的消息
public void readInfo() {
try {
ByteBuffer buffer = ByteBuffer.allocate(1024);
socketChannel.read(buffer);
String msg = new String(buffer.array());
System.out.println(msg.trim());
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
//启动客户端
GroupChatClient chatClient = new GroupChatClient();
//启动一个线程,每隔3秒,读取从服务器发送数据
new Thread(() -> {
while (true) {
chatClient.readInfo();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
//获取用户输入,发送到服务器
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
String s = scanner.nextLine();
chatClient.sendInfo(s);
}
}
}