NIO实现简单的聊天群
//服务器端
public class GroupChatSever {
private final static int PORT = 6666;//监听端口
private Selector selector;//选择器
private ServerSocketChannel serverSocketChannel;
public GroupChatSever(){
try{
selector = Selector.open();//开启选择器
serverSocketChannel = ServerSocketChannel.open();//开启通道
serverSocketChannel.configureBlocking(false);//将通道设为非阻塞状态
serverSocketChannel.socket().bind(new InetSocketAddress(PORT));//通道绑定监听端口
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);//将通道注册到选择器上,事件类型为接收
listen();
}catch (IOException e){
e.printStackTrace();
}
}
//对端口进行监听
public void listen(){
try {
while (true){
//检查注册通道是否有事件发生,检查时长为2秒
int count = selector.select(2000);
if (count > 0){//如果注册通道有事件发生则进行处理
//获取所有发生事件的通道对应的SelectionKey
Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
while (keyIterator.hasNext()){
SelectionKey key = keyIterator.next();
if (key.isAcceptable()){//判断该key对应的通道是否需进行接收操作
//虽然accept()方法是阻塞的,但是因为对通道进行过判断,
//可以确定是有客户端连接的,所以此时调用accept并不会阻塞
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
//接收后,将获取的客户端通道注册到选择器上,事件类型为读
socketChannel.register(selector, SelectionKey.OP_READ);
System.out.println(socketChannel.getRemoteAddress() + "上线!");
}
if (key.isReadable()){//判断该key对应的通道是否需进行读操作
readFromClient(key);
}
//注意当处理完一个通道key时,需将它从迭代器中移除
keyIterator.remove();
}
}
}
}catch (IOException e){
e.printStackTrace();
}
}
/**
* 读取客户端发来的消息
* @param key 需读取的通道对应的SelectionKey
*/
public void readFromClient(SelectionKey key){
SocketChannel socketChannel = null;
try{
//通过SelectionKey获取对应通道
socketChannel = (SocketChannel)key.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
int read = socketChannel.read(byteBuffer);
if (read > 0){
String message = new String(byteBuffer.array());
System.out.println("客户端: " + message);
sendToOtherClient(message, socketChannel);
}
}catch (IOException e){
//这里做了简化,将所有异常都当做是客户端断开连接触发的异常,实际项目中请不要这样做
try{
System.out.println(socketChannel.getRemoteAddress() + "下线");
key.cancel();//将该SelectionKey撤销
socketChannel.close();//再关闭对应通道
}catch (IOException e2){
e2.printStackTrace();
}
}
}
/**
* 将客户端发送的消息转发到其他客户端
* @param message 转发的消息
* @param from 发送消息的客户端通道
* @throws IOException
*/
public void sendToOtherClient(String message, SocketChannel from) throws IOException{
System.out.println("消息转发中......");
for (SelectionKey key : selector.keys()){//遍历选择器中所有SelectionKey
Channel channel = key.channel();//根据SelectionKey获取对应通道
//排除掉发送消息的通道,将消息写入到其他客户端通道
if (channel instanceof SocketChannel && channel != from){
SocketChannel socketChannel = (SocketChannel)channel;
ByteBuffer byteBuffer = ByteBuffer.wrap(message.getBytes());
socketChannel.write(byteBuffer);
}
}
}
public static void main(String[] args) {
GroupChatSever groupChatSever = new GroupChatSever();
}
}
//客户端
public class GroupChatClient {
private final static String SEVER_HOST = "127.0.0.1";//连接的客户端主机
private final static int SEVER_PORT = 6666;//连接的客户端端口
private Selector selector;//选择器
private SocketChannel socketChannel;
private String username;//储存客户端ip地址
public GroupChatClient(){
try {
selector = Selector.open();//开启选择器
socketChannel = SocketChannel.open(new InetSocketAddress(SEVER_HOST, SEVER_PORT));//开启通道
socketChannel.configureBlocking(false);//将通道设为非阻塞
socketChannel.register(selector, SelectionKey.OP_READ);//将通道注册在选择器上,事件类型为读
username = socketChannel.getLocalAddress().toString().substring(1);//获取客户端ip地址
String message = " 进入聊天群!";
sendMessage(message);
}catch (IOException e){
e.printStackTrace();
}
}
//发送消息
public void sendMessage(String message){
message = username+": "+message;
try{
ByteBuffer byteBuffer = ByteBuffer.wrap(message.getBytes());
socketChannel.write(byteBuffer);
}catch (IOException e){
e.printStackTrace();
}
}
//读取从服务器转发送过来的消息
public void readMessage(){
try{
int read = selector.select();
if (read > 0){
Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
while (keyIterator.hasNext()){
SelectionKey key = keyIterator.next();
if (key.isReadable()){
SocketChannel socketChannel = (SocketChannel)key.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
socketChannel.read(byteBuffer);
System.out.println(new String(byteBuffer.array()));
}
keyIterator.remove();
}
}
}catch (IOException e){
e.printStackTrace();
}
}
public static void main(String[] args) {
final GroupChatClient groupChatClient = new GroupChatClient();
//客户端开启一个线程来监听是否有服务器转发来消息
new Thread(){
@Override
public void run() {
while (true){
groupChatClient.readMessage();
try {
Thread.currentThread().sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}.start();
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()){
String message = scanner.nextLine();
groupChatClient.sendMessage(message);
}
}
}
尚学堂给同学们带来全新的Java300集课程啦!java零基础小白自学Java必备优质教程_手把手图解学习Java,让学习成为一种享受_哔哩哔哩_bilibili尚学堂给同学们带来全新的Java300集课程啦本课程为Java300集2022版第一季,配合最新版的Java课程,所有视频重新录制,课件所有图形做了重新绘制和配色,图解学习Java,让学习成为一种享受本套教程专门为零基础学员而制,适合准备入行Java开发的零基础学员,视频中穿插多个实战项目。每一个知识点都讲解的通俗易懂,由浅入深。不仅适用于零基础的初学者,有经验的程序员也可做巩固学习。后续课
https://www.bilibili.com/video/BV1qL411u7eE?spm_id_from=333.999.0.0