1. 服务端

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set; public class GroupChatServer {
private Selector selector;
private ServerSocketChannel listenChannel;
private static final int PORT = 8888; // 构造 器
public GroupChatServer() {
try {
selector = Selector.open();
listenChannel = ServerSocketChannel.open();
// 绑定端口
listenChannel.socket().bind(new InetSocketAddress(PORT));
// 设置非阻塞模式
listenChannel.configureBlocking(false);
// 将listenChannel注册到selector
listenChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (Exception e) {
e.printStackTrace();
}
} /**
* 监听
*/
public void listen() {
try {
while (true) {
//select(2000) 只阻塞2秒
// int count = selector.select(2000);
// select()方法一直阻塞
int count = selector.select();
if (count > 0) {
// 遍历得到所有的SelectionKey集合 Iterator<SelectionKey> keysIterator = selector.selectedKeys().iterator();
while (keysIterator.hasNext()) {
// 处理每个selectionKey
SelectionKey selectionKey = keysIterator.next();
// 监听到连接事件
if (selectionKey.isAcceptable()) {
SocketChannel socketChannel = listenChannel.accept();
socketChannel.configureBlocking(false);
//注册
socketChannel.register(selector, SelectionKey.OP_READ);
// 提示上线
System.out.println(socketChannel.getRemoteAddress() + "上线");
}
// 通道可读事件
if (selectionKey.isReadable()) {
// todo 处理读
readMessage(selectionKey);
}
// 删除key,防止重复处理
keysIterator.remove();
}
} else {
// System.out.println("等待中。。。。");
}
}
} catch (Exception e) {
e.printStackTrace();
} } /**
* 读取客户端消息
*
* @param key
*/
public void readMessage(SelectionKey key) {
SocketChannel socketChannel = null;
try {
socketChannel = (SocketChannel) key.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
int read = socketChannel.read(byteBuffer);
// 根据read值做处理,如果read > 0 说明真的读取到数据了
if (read > 0) {
String message = new String(byteBuffer.array());
System.out.println("Form Client : " + message);
// todo 向其它客户端 转发消息
sendInfoToOtherClient(message, socketChannel);
} } catch (IOException e) {
try {
System.out.println(socketChannel.getRemoteAddress() + "离线了。。。");
// 离线之后取消注册
key.cancel();
// 关闭channel
socketChannel.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
} /**
* 转发消息到其它客户端
*
* @param message 转发的消息
* @param self : 排除的channel
*/
public void sendInfoToOtherClient(String message, SocketChannel self) throws IOException {
System.out.println("服务器转发消息中。。。");
// 遍历所有注册到selector上的socketChannel,并排除自己
Set<SelectionKey> keys = selector.keys();
for (SelectionKey key : keys) {
// 通过key取出对应的SocketChannel
Channel targetChannel = key.channel();
// 排除自己
if (targetChannel instanceof SocketChannel && targetChannel != self) {
SocketChannel target = (SocketChannel) targetChannel;
// 将message 存储到buffer
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
// 将buffer中的数据写入通道
target.write(buffer);
} }
} public static void main(String[] args) {
//创建对象
GroupChatServer chatServer = new GroupChatServer();
chatServer.listen();
}
}

2. 客户端

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 {
// 服务器ip
private final String HOST = "127.0.0.1";
// 服务器端口
private final int PORT = 8888;
private Selector selector;
private SocketChannel socketChannel;
private String username; public GroupChatClient() {
try {
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);
System.out.println(username + " ok!");
} catch (Exception e) {
e.printStackTrace();
}
} /**
* 向服务端发送消息
*
* @param info 消息内容
*/
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(2000);
if (readChannels > 0) {
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> keyInterator = keys.iterator(); while (keyInterator.hasNext()) {
SelectionKey selectionKey = keyInterator.next();
if (selectionKey.isReadable()) {
// 得到读相关通道
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
socketChannel.read(byteBuffer);
//把buffer中的数据转成字符 串
String messge = new String(byteBuffer.array());
System.out.println( messge.trim());
}
//删除当前selectionKey
keyInterator.remove();
} } else {
// System.out.println("没有可用通道。。。。") }
} catch (IOException e) {
e.printStackTrace();
}
} public static void main(String[] args) {
// 启动客户端
GroupChatClient chatClient = new GroupChatClient(); // 启动一个线程每隔2秒读取从服务端发送过来的数据
new Thread() {
@Override
public void run() {
while (true) {
chatClient.readInfo();
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start(); // 发送数据到服务端
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
String info = scanner.next();
chatClient.sendInfo(info);
} }
}

  

NIO编程之多客户端聊天系统的更多相关文章

  1. JDK NIO编程

    我们首先需要澄清一个概念:NIO到底是什么的简称?有人称之为New I/O,因为它相对于之前的I/O类库是新增的,所以被称为New I/O,这是它的官方叫法.但是,由于之前老的I/O类库是阻塞I/O, ...

  2. Reactor 典型的 NIO 编程模型

    Doug Lea 在 Scalable IO in Java 的 PPT 中描述了 Reactor 编程模型的思想,大部分 NIO 框架和一些中间件的 NIO 编程都与它一样或是它的变体.本文结合 P ...

  3. Java IO编程全解(四)——NIO编程

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7793964.html 前面讲到:Java IO编程全解(三)——伪异步IO编程 NIO,即New I/O,这 ...

  4. NIO和IO(BIO)的区别及NIO编程介绍

    IO(BIO)和NIO的区别:其本质就是阻塞和非阻塞的区别. 阻塞概念:应用程序在获取网络数据的时候,如果网络传输数据很慢,那么程序就一直等着,直到传输完毕为止. 非阻塞概念:应用程序直接可以获取已经 ...

  5. Nio编程模型总结

    终于,这两天的考试熬过去了, 兴致冲冲的来整理笔记来, 这篇博客是我近几天的NIO印象笔记汇总,记录了对Selector及Selector的重要参数的理解,对Channel的理解,常见的Channel ...

  6. NIO 编程模型

    NIO 编程模型 Doug Lea 在 Scalable IO in Java 的 PPT 中描述了 Reactor 编程模型的思想,大部分 NIO 框架和一些中间件的 NIO 编程都与它一样或是它的 ...

  7. 手动搭建I/O网络通信框架3:NIO编程模型,升级改造聊天室

    第一章:手动搭建I/O网络通信框架1:Socket和ServerSocket入门实战,实现单聊 第二章:手动搭建I/O网络通信框架2:BIO编程模型实现群聊 在第二章中用BIO编程模型,简单的实现了一 ...

  8. 深入学习Netty(2)——传统NIO编程

    前言 学习Netty编程,避免不了从了解Java 的NIO编程开始,这样才能通过比较让我们对Netty有更深的了解,才能知道Netty大大的好处.传统的NIO编程code起来比较麻烦,甚至有遗留Bug ...

  9. 循序渐进Socket网络编程(多客户端、信息共享、文件传输)

    循序渐进Socket网络编程(多客户端.信息共享.文件传输) 前言:在最近一个即将结束的项目中使用到了Socket编程,用于调用另一系统进行处理并返回数据.故把Socket的基础知识总结梳理一遍. 1 ...

随机推荐

  1. 修改JAVA_HOME失效

    在修改JDK的安装目录的情况下会出现失效的时候,因为jdk在安装的时候自己在path中添加了 C:\ProgramData\Oracle\Java\javapath 这个路径. 解决: 删除 path ...

  2. yolov--7--解决报错:/bin/sh: 1: nvcc: not found make: *** [obj/convolutional_kernels.o] Error 127

    1.配置darknet配置darknet出现错误: qhy@qhy-desktop:~/darknet$ make cleanqhy@qhy-desktop:~/darknet$ make……gcc ...

  3. Proteus报错处理经验:power rails ‘GND’ and 'VCC/VDD' are interconnected in net VCC

    1 前言 初学Proteus,画好原理图后遇到了power rails 'GND' and 'VCC/VDD' are interconnected in net VCC的报错. 尝试了网上的解决办法 ...

  4. 今天起,重新开头学习Java - 一、安装环境

    先拜领路人 https://blog.csdn.net/u011541946/article/category/6951961/3? 一.安装JDK 1. 下载 www.java.com JDK是Ja ...

  5. Jmeter使用SSL(HTTPS协议)

    Jmeter是apache一款开源.小巧的性能测试工具,平时测试web http协议经常使用,其实jmeter同样支持ssl.方法如下: 需要装有目标网站证书的密钥库,即testclient.keys ...

  6. [Python3] 005 列表的基本使用

    目录 1. 列表概述 2. 创建列表 3. 列表常用操作 (1) 访问列表 (2) 分片操作 1) 正向操作 2) 反向操作 3) 内置函数 id() 加入队伍 1. 列表概述 一组有顺序的数据的组合 ...

  7. TimeUnit类 java.util.concurrent.TimeUnit

    TimeUnit是什么? TimeUnit是java.util.concurrent包下面的一个类,表示给定单元粒度的时间段 主要作用 时间颗粒度转换 延时 常用的颗粒度 TimeUnit.DAYS ...

  8. HTTP协议详解??

    HTTP协议: HTTP (hypertext transport protocol) , 即 超 文 本 传 输 协 议 . 这 个 协 议 详 细 规 定 了 浏 览 器 和 万 维 网 服 务 ...

  9. B.Petr and a Combination Lock

    https://codeforces.com/contest/1097/problem/A Petr and a Combination Lock time limit per test 1 seco ...

  10. Neo4j : 通过节点的 id属性 对节点进行查,改,删操作

    1. "查"操作 , 查找 id 属性 为 501的节点: MATCH (r) WHERE id(r) = 501 RETURN r 2. "改"操作, 更改 ...