Java NIO实现群聊系统

网友投稿 249 2022-09-13


Java NIO实现群聊系统

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

前面的文章介绍了NIO的三大核心组件并编写了BIO的一个demo实例,本文使用NIO写一个小应用实例,巩固并加深对NIO的理解。

实例要求:

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

2)实现多人群聊

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

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

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

服务端代码:

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.socketdarvqVuUgJ().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 iterator = selector.selectedKeys().iterator();

while (iterator.hasNext()) {

//取出selectionkey

SelectionKey key = iterator.next();

//监听到accept

if(key.isAcceptable()) {

SocketChannel sc = listenChannel.accept();

sc.configureBlocking(false);

//将该 shttp://c 注册到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);

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

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

}

}

//可以写一个Handler

class MyHandler {

public void readData() {

}

public void sendInfoToOtherClients(){

}

}

客户端代码:

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 {

//定义相关的属性

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("127.0.0.1", 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 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);

}

}

}

注意:必须设置通道为非阻塞,才能向Selector注册,否则报 java.nio.channels.IllegalBlockingModeException 错

注意:在客户端上要想获取得到服务端的数据,也需要注册在register上(监听读事件)


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:三次握手四次断开(易懂版)
下一篇:简单网络管理SNMP杂谈(snmp的网络架构)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~