Java基于NIO实现群聊系统

本文实例为大家分享了Java基于NIO实现群聊系统的具体代码,供大家参考,具体内容如下

实例要求:

1.编写一个 NIO 群聊系统,实现服务器端和客户端之间的数据简单通讯(非阻塞)

2.实现多人群聊

3.服务器端:可以监测用户上线,离线,并实现消息转发功能

4.客户端:通过 Channel 可以无阻塞发送消息给其它所有用户,同时可以接受其它用户发送的消息(有服务器转发得到)

5.目的:进一步理解 NIO 非阻塞网络编程机制

6.示意图分析和代码

// 服务端:

package com.atguigu.nio.groupchat;

import java.io.IOException;

import java.net.InetSocketAddress;

import java.nio.ByteBuffer;

import java.nio.channels.Channel;

import java.nio.channels.SelectionKey;

import java.nio.channels.Selector;

import java.nio.channels.ServerSocketChannel;

import java.nio.channels.SocketChannel;

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() {

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 {

//发生异常处理....

}

}

//读取客户端消息

public void readData(SelectionKey key) {

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);

//向其它的客户端转发消息(去掉自己),专门写一个方法来处理

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("服务器转发消息中...");

//遍历所有注册到 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();

}

}

// 客户端:

package com.atguigu.nio.groupchat;

~~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;

public class GroupChatClient {

//定义相关的属性

private final String HOST = "127.0.0.1";//服务器的ip

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);

//将 channel 注册到selector

socketChannel.register(selector, SelectionKey.OP_READ);

//得到 username

username = socketChannel.getLocalAddress().toString().substring(1);

System.out.println(username + " is ok...");

}

//向服务器发送消息

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) {//有可以用的通道

Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

while (iterator.hasNext()) {

SelectionKey key = iterator.next();

if (key.isReadable()) {

//得到相关的通道

SocketChannel sc = (SocketChannel) key.channel();

//得到一个 Buffer

ByteBuffer buffer = ByteBuffer.allocate(1024);

//读取

sc.read(buffer);

//把读到的缓冲区的数据转成字符串

String msg = new String(buffer.array());

System.out.println(msg.trim());

}

}

iterator.remove(); //删除当前的 selectionKey,防止重复操作

} else {

//System.out.println("没有可以用的通道...");

}

} catch (Exception e) {

e.printStackTrace();

}

}

public static void main(String[] args) throws Exception {

//启动我们客户端

GroupChatClient chatClient = new GroupChatClient();

//启动一个线程,每个 3 秒,读取从服务器发送数据

new Thread() {

public void run() {

while (true) {

chatClient.readInfo();

try {

Thread.currentThread().sleep(3000);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}.start();

//发送数据给服务器端

Scanner scanner = new Scanner(System.in);

while (scanner.hasNextLine()) {

String s = scanner.nextLine();

chatClient.sendInfo(s);

}

}

}

运行结果

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

以上是 Java基于NIO实现群聊系统 的全部内容, 来源链接: utcz.com/p/250965.html

回到顶部