Java?NIO實現(xiàn)聊天系統(tǒng)
更新時間:2021年11月24日 12:11:49 作者:菜鳥程序猿進(jìn)階之路
這篇文章主要為大家詳細(xì)介紹了Java?NIO實現(xiàn)聊天系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
使用Java的NIO寫的一個小的聊天系統(tǒng),供大家參考,具體內(nèi)容如下
一、服務(wù)端
/**
* 群聊的服端
*
* @author :breakpoint/趙立剛
* @date : 2020/08/13
*/
public class GroupChatServer {
// 定義相關(guān)的屬性
private Selector selector;
private ServerSocketChannel listenChannel;
private static final int port = 6667;
// 構(gòu)造器
// 進(jìn)行初始化的操作
public GroupChatServer() {
try {
// 獲取選擇器
selector = Selector.open();
// 獲取到 listenChannel
listenChannel = ServerSocketChannel.open();
// 設(shè)定端口
listenChannel.bind(new InetSocketAddress(port));
// 設(shè)定非阻塞模式
listenChannel.configureBlocking(false);
// 將該 listenChannel 注冊到 selector上 完成操作
listenChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服務(wù)器啟動了。。。。");
} catch (IOException e) {
}
}
// 監(jiān)聽的代碼
public void listen() {
try {
// 循環(huán)處理
while (true) {
int count = selector.select(2000);
if (count > 0) {
// 有事件需要處理
// 遍歷處理 得到selectionKeys集合
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> selectionKeyIterator = selectionKeys.iterator();
while (selectionKeyIterator.hasNext()) {
// 得到selectionKey
SelectionKey selectionKey = selectionKeyIterator.next();
// 監(jiān)聽到了 accept
if (selectionKey.isAcceptable()) {
// 獲取到連接
SocketChannel sc = listenChannel.accept();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
// 提示上線
System.out.println(sc.getRemoteAddress() + ":上線啦。。。。");
}
if (selectionKey.isReadable()) {
// 讀取事件 通道是可以讀的狀態(tài) //專門寫
readData(selectionKey);
}
// 移除當(dāng)前的刪除 防止重復(fù)處理操作
selectionKeyIterator.remove();
}
} else {
System.out.println("等待中。。。。。。");
}
}
} catch (Exception e) {
} finally {
}
}
// 讀取客戶端的消息
private void readData(SelectionKey selectionKey) {
// 獲取 socketChannel
SocketChannel channel = null;
try {
channel = (SocketChannel) selectionKey.channel();
ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment();
int count = channel.read(byteBuffer);
// 分情況處理
if (count > 0) {
// 獲取到數(shù)據(jù)專程
String msg = new String(byteBuffer.array(), 0, count);
byteBuffer.clear();
System.out.println(channel.getRemoteAddress() + "來自客戶端" + msg);
// 向其他的客戶端轉(zhuǎn)發(fā)消息
sendInfoToOtherClients(msg, channel);
}
} catch (IOException e) {
// 如果發(fā)生異常 提示說明離線了
try {
System.out.println(channel.getRemoteAddress() + "離線了。。。。");
// 取消注冊
selectionKey.cancel();
// 關(guān)閉通道
channel.close();
} catch (IOException e1) {
//e1.printStackTrace();
}
} finally {
}
}
// 轉(zhuǎn)發(fā)消息給其他的客戶端 去掉自己的客戶端
private void sendInfoToOtherClients(String msg, SocketChannel self) throws IOException {
System.out.println("服務(wù)器轉(zhuǎn)發(fā)消息。。。。。");
// 進(jìn)行遍歷操作
Set<SelectionKey> keys = selector.keys();
for (SelectionKey key : keys) {
// 取出來所有的
Channel targetChannel = key.channel();
// 排除自己
if (targetChannel instanceof SocketChannel && targetChannel != self) {
SocketChannel dest = (SocketChannel) targetChannel;
ByteBuffer byteBuffer = ByteBuffer.wrap(msg.getBytes());
// 發(fā)送數(shù)據(jù)
dest.write(byteBuffer);
}
}
}
public static void main(String[] args) {
GroupChatServer groupChatServer = new GroupChatServer();
groupChatServer.listen();
}
}
二、客戶端代碼
/**
* @author :breakpoint/趙立剛
* @date : 2020/08/13
*/
public class GroupChatClient {
// 定義相關(guān)屬性
private final String HOST = "127.0.0.1"; //服務(wù)器地址
private final int port = 6667; // 服務(wù)器端口
private Selector selector;
private SocketChannel socketChannel;
private String userName;
// 完成初始化工作
public GroupChatClient() {
try {
selector = Selector.open();
// 連接服務(wù)器
socketChannel = SocketChannel.open(new InetSocketAddress(HOST, port));
// 設(shè)置非阻塞工作
socketChannel.configureBlocking(false);
// 注冊我們的通道
socketChannel.register(selector, SelectionKey.OP_READ);
userName = socketChannel.getLocalAddress().toString();
System.out.println("客戶端專備好啦");
} catch (IOException e) {
}
}
public void sendInfo(String info) {
String msg = userName + "說:" + info;
try {
ByteBuffer wrap = ByteBuffer.wrap(msg.getBytes());
socketChannel.write(wrap);
} catch (IOException e) {
e.printStackTrace();
}
}
// 讀取信息
public void readInfo() {
try {
int readChannel = selector.select(2000);
if (readChannel > 0) {
// 有可以用的通道
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey next = iterator.next();
if (next.isReadable()) {
SelectableChannel keyChannel = next.channel();
if (keyChannel instanceof SocketChannel) {
// 獲取到我們的通道
SocketChannel channel = (SocketChannel) keyChannel;
ByteBuffer allocate = ByteBuffer.allocate(1024);
// 讀取數(shù)據(jù)
int read = channel.read(allocate);
if (read > 0) {
// 輸出我們的消息
System.out.println(new String(allocate.array(), 0, read));
}
}// end if
}
iterator.remove();
}
} else {
System.out.println("沒有可用的通道");
}
} catch (IOException e) {
}
}
public static void main(String[] args) throws Exception {
// 啟動客戶端的操作
final GroupChatClient groupChatClient = new GroupChatClient();
// 啟動一個線程
new Thread(() -> {
while (true) {
groupChatClient.readInfo();
try {
Thread.currentThread().sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
// 輸入信息
String s = scanner.nextLine();
groupChatClient.sendInfo(s);
}
System.in.read();
}
}
三、運行的結(jié)果


以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。?
相關(guān)文章
java開發(fā)MVC三層架構(gòu)上再加一層Manager層原理詳解
這篇文章主要為大家介紹了MVC三層架構(gòu)中再加一層Manager層原理的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-10-10
Java中static修飾的靜態(tài)變量、方法及代碼塊的特性與使用
這篇文章主要介紹了Java中static修飾的靜態(tài)變量、方法及代碼塊的特性與使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
基于JAVA中Jersey處理Http協(xié)議中的Multipart的詳解
之前在基于C#開發(fā)彩信用最原始的StringBuilder拼接字符串方式處理過Multipart?,F(xiàn)在在做一個項目的時候,由于之前的技術(shù)路線都是使用Jersey處理Http這塊,為了保持技術(shù)路線一致,研究了一下如何使用Jersey處理Http協(xié)議中的Multipart2013-05-05

