要求
1)编写一个NIO群聊系统,实现服务器端和客户端之间的数据简单通讯
2)实现多人聊天
3)服务器端:可以检测用户上线,离线,并实现消息转发功能
4)客户端:通过channel可以无阻塞发送消息给其他所有用户,同时可以接受其他用户发送的消息
服务端
package com.dd.nio.groupchat;
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 = 6667;
//构造器
public GroupChatServer(){
try {
//得到选择器
selector = Selector.open();
listenChannel = ServerSocketChannel.open();
//绑定端口
listenChannel.socket().bind(new InetSocketAddress(PORT));
//设置非阻塞模式
listenChannel.configureBlocking(false);
//将该listenChannel注册到selectorshang上
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){//有事件处理
//遍历得到的selectionKey集合
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()){
//取出selectionKey
SelectionKey key = iterator.next();
//监听到连接事件
if (key.isAcceptable()){
SocketChannel socketChannel = listenChannel.accept();
socketChannel.configureBlocking(false);
//将该socketChannel注册到selector上
socketChannel.register(selector,SelectionKey.OP_READ);
//提示某某上线
System.out.println(socketChannel.getRemoteAddress()+"上线");
}
//读取数据事件
if(key.isReadable()){//通道是可读状态
readData(key);
}
//当前的key删除,防止重复处理
iterator.remove();
}
}else {
System.out.println("等待连接");
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
}
}
//读取客户端消息
private void readData(SelectionKey key){
//定义一个socketChannel
SocketChannel channel = null;
try {
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);
//向其他的客户端转发消息
sendInfoToOtherClients(msg,channel);
}
}catch (IOException e){
try {
System.out.println(channel.getRemoteAddress()+"离线");
//取消注册,关闭通道
key.cancel();
channel.close();
} catch (IOException ex) {
ex.printStackTrace();
}
e.printStackTrace();
}
}
//z转发到其他客户端
private void sendInfoToOtherClients(String msg,SocketChannel self) throws IOException{
//遍历所有注册到selector上的socketChannel,并排除自己
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 groupChatServer = new GroupChatServer();
groupChatServer.listen();
}
}
客户端
package com.dd.nio.groupchat;
import javafx.beans.binding.When;
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.util.Iterator;
import java.util.Scanner;
import java.util.Set;
public class GroupChatClient {
//定义相关属性
private final String HOST = "127.0.0.1";
private final int PORT = 6667;
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);
socketChannel.register(selector, SelectionKey.OP_READ);
userName = socketChannel.getLocalAddress().toString().substring(1);
}
//向服务器发送消息
public void sendInfo(String info){
info = userName+"说:"+info;
try {
socketChannel.write(ByteBuffer.wrap(info.getBytes()));
}catch (IOException e){
e.printStackTrace();
}
}
//读取服务器端的消息
public void readInfo(){
try {
//没写参数 ,此时这里阻塞
int readChannels = selector.select();
if (readChannels > 0){
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()){
SelectionKey next = iterator.next();
if (next.isReadable()){
//得到相关的通道
SocketChannel channel = (SocketChannel)next.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
channel.read(buffer);
String msg = new String(buffer.array());
System.out.println(msg.trim());
}
iterator.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception{
//启动客户端
GroupChatClient groupChatClient = new GroupChatClient();
//启动一个线程,每隔3秒从服务器端发送的数据
new Thread(){
@Override
public void run() {
while (true){
groupChatClient.readInfo();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
//发送数据给服务器
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()){
String s = scanner.nextLine();
groupChatClient.sendInfo(s);
}
}
}