Java基于NIO實(shí)現(xiàn)群聊功能
本文實(shí)例為大家分享了Java基于NIO實(shí)現(xiàn)群聊功能的具體代碼,供大家參考,具體內(nèi)容如下
一、群聊服務(wù)器
package com.dashu.netty.group_chat;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
public class GroupChatServer {
/**
* 初始化選擇器
*/
private Selector selector;
/**
* 初始化服務(wù)器網(wǎng)絡(luò)通道
*/
private ServerSocketChannel serverSocketChannel;
/**
* 端口
*/
private static final int PORT = 6666;
/**
* 構(gòu)造方法
*/
public GroupChatServer() {
try {
//獲取選擇器
selector = Selector.open();
//獲取服務(wù)器網(wǎng)絡(luò)通道
serverSocketChannel = ServerSocketChannel.open();
//網(wǎng)絡(luò)地址
InetSocketAddress inetSocketAddress = new InetSocketAddress(PORT);
//服務(wù)器網(wǎng)絡(luò)通道綁定網(wǎng)絡(luò)地址
serverSocketChannel.socket().bind(inetSocketAddress);
//設(shè)置服務(wù)器網(wǎng)絡(luò)通道非阻塞
serverSocketChannel.configureBlocking(false);
//將服務(wù)器網(wǎng)絡(luò)通道注冊(cè)到選擇器上,綁定連接請(qǐng)求事件
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 監(jiān)聽(tīng)客戶端請(qǐng)求事件
*/
public void listen() {
try {
//無(wú)限循環(huán)
while (true) {
//獲取請(qǐng)求數(shù)
int count = selector.select();
//count大于0,則代表有請(qǐng)求進(jìn)來(lái)
if (count > 0) {
//獲取請(qǐng)求集
Iterator<SelectionKey> selectionKeyIterator = selector.selectedKeys().iterator();
//遍歷請(qǐng)求集
while (selectionKeyIterator.hasNext()) {
//得到請(qǐng)求
SelectionKey selectionKey = selectionKeyIterator.next();
//連接請(qǐng)求
if (selectionKey.isAcceptable()) {
//獲取客戶端網(wǎng)絡(luò)通道
SocketChannel socketChannel = serverSocketChannel.accept();
//設(shè)置客戶端網(wǎng)絡(luò)通道非阻塞
socketChannel.configureBlocking(false);
//將客戶端網(wǎng)絡(luò)通道注冊(cè)到選擇器上
socketChannel.register(selector, SelectionKey.OP_READ);
System.out.println(socketChannel.getRemoteAddress() + "上線了");
}
//信息讀取請(qǐng)求
if (selectionKey.isReadable()) {
//客戶端信息讀取
readData(selectionKey);
}
//移除請(qǐng)求
selectionKeyIterator.remove();
}
} else {
System.out.println("等待...");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 客戶端信息讀取
*
* @param selectionKey
*/
private void readData(SelectionKey selectionKey) {
//初始化客戶端網(wǎng)絡(luò)通道
SocketChannel socketChannel = null;
try {
//獲取客戶端網(wǎng)絡(luò)通道
socketChannel = (SocketChannel) selectionKey.channel();
//創(chuàng)建緩沖區(qū)
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
//讀取客戶端網(wǎng)絡(luò)通道中的數(shù)據(jù)到緩沖區(qū)
int count = socketChannel.read(byteBuffer);
//判斷緩沖區(qū)中是否有數(shù)據(jù)
if (count > 0) {
//將緩沖區(qū)的數(shù)據(jù)轉(zhuǎn)換位字符串
String message = new String(byteBuffer.array());
System.out.println(message.trim());
//將信息群發(fā)到其他客戶端
sendInfoToOtClients(message, socketChannel);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 將信息群發(fā)到其他客戶端
*
* @param message
* @param socketChannel
*/
private void sendInfoToOtClients(String message, SocketChannel socketChannel) {
//獲取所有注冊(cè)到選擇器的客戶端,并遍歷
for (SelectionKey selectionKey : selector.keys()) {
//獲取通道
Channel channel = selectionKey.channel();
//判斷通道是否屬于SocketChannel,同時(shí)不等于發(fā)送信息的客戶端
if (channel instanceof SocketChannel && channel != socketChannel) {
//通道轉(zhuǎn)換
SocketChannel sc = (SocketChannel) channel;
//將信息寫入緩沖區(qū)
ByteBuffer byteBuffer = ByteBuffer.wrap(message.getBytes(StandardCharsets.UTF_8));
try {
//將緩沖區(qū)的數(shù)據(jù)寫入通道
sc.write(byteBuffer);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
GroupChatServer groupChatServer = new GroupChatServer();
System.out.println("服務(wù)器啟動(dòng),開(kāi)始監(jiān)聽(tīng)客戶端請(qǐng)求...");
groupChatServer.listen();
}
}
二、客戶端
package com.dashu.netty.group_chat;
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;
public class GroupChatClient {
/**
* 網(wǎng)絡(luò)連接地址
*/
private final String HOST = "127.0.0.1";
/**
* 端口
*/
private final int PORT = 6666;
/**
* 初始化選擇器
*/
private Selector selector;
/**
* 初始化網(wǎng)絡(luò)通道
*/
private SocketChannel socketChannel;
/**
* 用戶名
*/
private String username;
public GroupChatClient() {
try {
//獲取選擇器
selector = Selector.open();
//獲取服務(wù)器網(wǎng)絡(luò)地址
InetSocketAddress inetSocketAddress = new InetSocketAddress(HOST, PORT);
//獲取網(wǎng)絡(luò)通道
socketChannel = SocketChannel.open(inetSocketAddress);
//設(shè)置網(wǎng)絡(luò)通道非阻塞
socketChannel.configureBlocking(false);
//將網(wǎng)絡(luò)通道注冊(cè)到選擇器
socketChannel.register(selector, SelectionKey.OP_READ);
//獲取用戶名
System.out.println("請(qǐng)輸入用戶名:");
Scanner scanner = new Scanner(System.in);
username = scanner.nextLine();
System.out.println(username + " 進(jìn)入群聊...");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 向服務(wù)器發(fā)送信息
*
* @param message
*/
public void sendInfo(String message) {
message = username + ":" + message;
try {
//向通道寫入數(shù)據(jù)
socketChannel.write(ByteBuffer.wrap(message.getBytes(StandardCharsets.UTF_8)));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 讀取服務(wù)器發(fā)來(lái)的信息
*/
public void readInfo() {
try {
//獲取請(qǐng)求數(shù)
int count = selector.select();
if (count > 0) {
//獲取請(qǐng)求集
Iterator<SelectionKey> selectionKeyIterator = selector.selectedKeys().iterator();
//遍歷請(qǐng)求集
while (selectionKeyIterator.hasNext()) {
//獲取請(qǐng)求
SelectionKey selectionKey = selectionKeyIterator.next();
//判斷位讀請(qǐng)求
if (selectionKey.isReadable()) {
//獲取通道
SocketChannel sc = (SocketChannel) selectionKey.channel();
//創(chuàng)建緩沖區(qū)
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
//讀取通道的數(shù)據(jù)到緩沖區(qū)
sc.read(byteBuffer);
//緩沖區(qū)數(shù)據(jù)轉(zhuǎn)字符串
String message = new String(byteBuffer.array());
//輸出
System.out.println(message.trim());
}
//移除已完成請(qǐng)求
selectionKeyIterator.remove();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
GroupChatClient groupChatClient = new GroupChatClient();
/**
* 開(kāi)啟一個(gè)線程,每3秒讀取一次服務(wù)器發(fā)來(lái)的信息
*/
new Thread() {
@Override
public void run() {
while (true) {
groupChatClient.readInfo();
try {
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}.start();
//信息輸入
Scanner scanner = new Scanner(System.in);
System.out.println("請(qǐng)輸入信息:");
while (scanner.hasNextLine()) {
String s = scanner.nextLine();
//信息發(fā)送
groupChatClient.sendInfo(s);
System.out.println("請(qǐng)輸入信息:");
}
}
}
三、效果圖
1、服務(wù)器

2、客戶端01

3、客戶端02

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java?restTemplate發(fā)送get請(qǐng)求query參數(shù)傳遞問(wèn)題解決
這篇文章主要為大家介紹了Java?restTemplate發(fā)送get請(qǐng)求query參數(shù)傳遞問(wèn)題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
SpringMVC實(shí)現(xiàn)Validation校驗(yàn)過(guò)程詳解
Springboot集成kafka高級(jí)應(yīng)用實(shí)戰(zhàn)分享
JAVA線程sleep()和wait()詳解及實(shí)例
Spring?Boot面試必問(wèn)之啟動(dòng)流程知識(shí)點(diǎn)詳解

