JavaNIO Realization of Group Chat System
- 2021-12-13 08:10:28
- OfStack
In this paper, we share the specific code of Java NIO group chat system for your reference. The specific contents are as follows
The previous article introduces the three core components of NIO and compiles an demo example of BIO. This article uses NIO to write a small application example to consolidate and deepen the understanding of NIO.
Example requirements:
1) Write an NIO group chat system to realize simple data communication (non-blocking) between server and client
2) Realize multi-crowd chat
3) Server side: It can monitor users' online and offline, and realize message forwarding function
4) Client: Through channel, it can send messages to all other users without blocking, and at the same time, it can accept messages sent by other users (which are forwarded by the server)
5) Purpose: One step further to understand the NIO non-blocking network programming mechanism
Server-side code:
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();
//ServerSocketChannel
listenChannel = ServerSocketChannel.open();
//绑定端口
listenChannel.socket().bind(new InetSocketAddress(PORT));
//设置非阻塞模式
listenChannel.configureBlocking(false);
//将该listenChannel 注册到selector
listenChannel.register(selector, SelectionKey.OP_ACCEPT);
}catch (IOException e) {
e.printStackTrace();
}
}
//监听
public void listen() {
System.out.println("监听线程: " + Thread.currentThread().getName());
try {
//循环处理
while (true) {
int count = selector.select();
if(count > 0) {//有事件处理
//遍历得到selectionKey 集合
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
//取出selectionkey
SelectionKey key = iterator.next();
//监听到accept
if(key.isAcceptable()) {
SocketChannel sc = listenChannel.accept();
sc.configureBlocking(false);
//将该 sc 注册到seletor
sc.register(selector, SelectionKey.OP_READ);
//提示
System.out.println(sc.getRemoteAddress() + " 上线 ");
}
if(key.isReadable()) { //通道发送read事件,即通道是可读的状态
//处理读 (专门写方法..)
readData(key);
}
//当前的key 删除,防止重复处理
iterator.remove();
}
} else {
System.out.println("等待....");
}
}
}catch (Exception e) {
e.printStackTrace();
}finally {
//发生异常处理....
}
}
//读取客户端消息
private void readData(SelectionKey key) {
//取到关联的channle
SocketChannel channel = null;
try {
//得到channel
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("form 客户端: " + msg);
//向其它的客户端转发消息(去掉自己), 专门写1个方法来处理
sendInfoToOtherClients(msg, channel);
}
}catch (IOException e) {
try {
System.out.println(channel.getRemoteAddress() + " 离线了..");
//取消注册
key.cancel();
//关闭通道
channel.close();
}catch (IOException e2) {
e2.printStackTrace();;
}
}
}
//转发消息给其它客户(通道)
private void sendInfoToOtherClients(String msg, SocketChannel self ) throws IOException{
System.out.println("服务器转发消息中...");
System.out.println("服务器转发数据给客户端线程: " + Thread.currentThread().getName());
//遍历 所有注册到selector 上的 SocketChannel,并排除 self
for(SelectionKey key: selector.keys()) {
//通过 key 取出对应的 SocketChannel
Channel 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();
}
}
//可以写1个Handler
class MyHandler {
public void readData() {
}
public void sendInfoToOtherClients(){
}
}
Client code:
import java.io.IOException;
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.util.Iterator;
import java.util.Scanner;
import java.util.Set;
public class GroupChatClient {
// Defining Related Attributes
private final String HOST = "127.0.0.1"; // Server's ip
private final int PORT = 6667; // Server port
private Selector selector;
private SocketChannel socketChannel;
private String username;
// Constructor , Complete the initialization work
public GroupChatClient() throws IOException {
selector = Selector.open();
// Connect to the server
socketChannel = socketChannel.open(new InetSocketAddress("127.0.0.1", PORT));
// Set non-blocking
socketChannel.configureBlocking(false);
// Will channel Register to selector
socketChannel.register(selector, SelectionKey.OP_READ);
// Get username
username = socketChannel.getLocalAddress().toString().substring(1);
System.out.println(username + " is ok...");
}
// Send a message to the server
public void sendInfo(String info) {
info = username + " Say: " + info;
try {
socketChannel.write(ByteBuffer.wrap(info.getBytes()));
}catch (IOException e) {
e.printStackTrace();
}
}
// Read the message replied from the server
public void readInfo() {
try {
int readChannels = selector.select();
if(readChannels > 0) {// There are available channels
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
if(key.isReadable()) {
// Get the related channels
SocketChannel sc = (SocketChannel) key.channel();
// Get 1 A Buffer
ByteBuffer buffer = ByteBuffer.allocate(1024);
// Read
sc.read(buffer);
// Convert the read buffer data into a string
String msg = new String(buffer.array());
System.out.println(msg.trim());
}
}
iterator.remove(); // Delete the current selectionKey, Prevent repetitive operations
} else {
//System.out.println(" There is no available channel ...");
}
}catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
// Start our client
GroupChatClient chatClient = new GroupChatClient();
// Start 1 Threads , Every interval 3 Second, read the data sent from the server
new Thread() {
public void run() {
while (true) {
chatClient.readInfo();
try {
Thread.currentThread().sleep(3000);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
// Send data to the server
Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
String s = scanner.nextLine();
chatClient.sendInfo(s);
}
}
}
Note: You must set the channel to non-blocking to register with Selector, otherwise report java. nio. channels. IllegalBlockingModeException error
Note: If you want to get the data from the server on the client, you also need to register on register (listen for read events)