一、效果展示
- 服务器
- 客户端A
- 客户端B
二、服务端代码
public class ChatServer {
public static void main(String[] args) {
try {
//启动服务器
new ChatServer().startServer();
} catch (IOException e) {
e.printStackTrace();
//向客户端广播服务器宕机
}
}
//启动服务器
private void startServer() throws IOException {
//1.创建Selector
Selector selector = Selector.open();
//2.创建ServerSocketChannel
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8080));
//3.设置ServerSocketChannel非阻塞模式
serverChannel.configureBlocking(false);
//4.将ServerSocketChannel注册监听事件:有连接接入
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务器启动成功!");
//5.查询selector的选择键
for (;;){
int select = selector.select();
if (select<=0){
continue;
}
//5.1 循环遍历选择键,根据对应事件进行相关处理
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while(iterator.hasNext()){
SelectionKey selectionKey = iterator.next();
iterator.remove();
if (selectionKey.isAcceptable()){
//处理连接接入
handleAccept(serverChannel,selector);
}
if (selectionKey.isReadable()){
//处理信息接收
handleRead(selectionKey,selector);
}
}
}
}
//处理信息接收
private void handleRead(SelectionKey selectionKey, Selector selector) throws IOException {
//1.获取连接
SocketChannel channel = (SocketChannel) selectionKey.channel();
//2.读取信息
ByteBuffer buffer = ByteBuffer.allocate(1024);
String message="";
int length;
if ((length=channel.read(buffer))!=-1){
buffer.flip();
message=new String(buffer.array(),0,length);
buffer.clear();
}
//3.判断客户端是否退出聊天室
if ("exit".equalsIgnoreCase(message)){
channel.close();
}
channel.register(selector,SelectionKey.OP_READ);
if (message.length()>0 && !"exit".equalsIgnoreCase(message)){
System.out.println(message);
//4.广播信息
radioMessage(message,selector,channel);
}
}
//广播信息
private void radioMessage(String message, Selector selector, SocketChannel channel) throws IOException {
//1.获取所有已经接入 channel
Set<SelectionKey> selectionKeys = selector.keys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()){
SelectionKey next = iterator.next();
//1.获取连接
Channel channel1 = next.channel();
//2.判断并给其他所有人广播信息
if(channel1 instanceof SocketChannel && channel1!=channel){
//2.1 发送信息
((SocketChannel)channel1).write(Charset.forName("UTF-8").encode(message));
}
}
}
//处理连接接入
private void handleAccept(ServerSocketChannel serverChannel, Selector selector) throws IOException {
//1.获取连接
SocketChannel accept = serverChannel.accept();
accept.configureBlocking(false);
//2.注册为可读连接
accept.register(selector,SelectionKey.OP_READ);
//3.发送欢迎信息
accept.write(Charset.forName("UTF-8").encode("欢迎进入聊天室!"));
}
}
三、客户端代码
启动类
public class ChatClient {
//启动客户端
public static void startClient() throws IOException {
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入昵称:");
String name=br.readLine();
//1.创建连接
SocketChannel channel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8080));
channel.configureBlocking(false);
//2.创建选择器并注册
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_READ);
//3.创建线程实现异步获取消息
new Thread(new AsynReceive(selector)).start();
//4.获取控制台输入并发送
String message;
ByteBuffer buffer = ByteBuffer.allocate(1024);
System.out.println("输入消息(exit 退出):");
while ((message=br.readLine())!=null && !"exit".equalsIgnoreCase(message)){
buffer.put(name.getBytes());
buffer.put(":".getBytes());
buffer.put(message.getBytes());
buffer.flip();
channel.write(buffer);
buffer.clear();
}
if ("exit".equalsIgnoreCase(message)){
buffer.put("exit".getBytes());
buffer.flip();
channel.write(buffer);
buffer.clear();
}
System.out.println("退出聊天室");
channel.close();
br.close();
}
}
异步接收信息类
public class AsynReceive implements Runnable{
private Selector selector;
public AsynReceive(Selector selector) {
this.selector = selector;
}
@Override
public void run() {
try {
for (;;){
int select = selector.select();
if (select<=0){
continue;
}
//循环遍历选择键,根据对应事件进行相关处理
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while(iterator.hasNext()){
SelectionKey selectionKey = iterator.next();
if (selectionKey.isReadable()){
//处理信息接收
handleRead(selectionKey,selector);
}
iterator.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
//处理信息接收
private void handleRead(SelectionKey selectionKey, Selector selector) throws IOException {
//1.获取连接
SocketChannel channel = (SocketChannel) selectionKey.channel();
//2.读取信息
ByteBuffer buffer = ByteBuffer.allocate(1024);
String message="";
int length;
if ((length=channel.read(buffer))!=-1){
buffer.flip();
message=new String(buffer.array(),0,length);
buffer.clear();
}
//3.判断客户端是否退出聊天室
if ("exit".equalsIgnoreCase(message)){
channel.close();
}
channel.register(selector,SelectionKey.OP_READ);
if (message.length()>0 && !"exit".equalsIgnoreCase(message)){
System.out.println(message);
}
}
}
创建客户端A
public class ClientA {
public static void main(String[] args) {
try {
ChatClient.startClient();
} catch (IOException e) {
e.printStackTrace();
}
}
}
创建客户端B
public class ClinetB {
public static void main(String[] args) {
try {
ChatClient.startClient();
} catch (IOException e) {
e.printStackTrace();
}
}
}