要求
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);
}
}
}