1.创建Nio服务端
package nio.study;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.Channel;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;
import javax.xml.ws.handler.MessageContext.Scope;
/**
*创建Nio服务端
*/
public class NIOServer {
/**
*启动
* @throws IOException
*/
public void start() throws IOException {
/**
* 1、 创建selector
*/
Selector selector = Selector.open();
/**
* 2、通过ServerScoketChannel创建channel通过
*/
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
/**
* 3、为channel通道绑定监听端口
*/
serverSocketChannel.bind(new InetSocketAddress(8000));
/**
* 4、**设置channel为非阻塞状态
*/
serverSocketChannel.configureBlocking(false);
/**
* 5、将channel注册到selector上 监听连接事件
*/
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务器启动成功!");
/**
* 6、循环等待新接入的连接
*/
for(;;) {
/**
* TODO 获取可用channel数量
*/
int readyChannels = selector.select();
/**
* TODO 为什么这样?
*/
if(readyChannels == 0) continue;
/**
*获取channel可用集合
*/
Set selectedKeys = selector.selectedKeys();
Iterator iterator = selectedKeys.iterator();
while(iterator.hasNext()) {
/**
*selectrionKey实例
*/
SelectionKey selectionKey = iterator.next();
/**
*移除Set中的当前selectionKey
*/
iterator.remove();
/**
* 7、根据就绪状态,调用对应方法处理业务逻辑
*/
/**
*如果是接入事件
*/
if(selectionKey.isAcceptable()) {
acceptHandler(serverSocketChannel, selector);
}
/**
*如果是可读事件
*/
if(selectionKey.isReadable()) {
readHandler(selectionKey, selector);
}
}
}
}
/**
*接入事件处理
* @throws IOException
*/
private void acceptHandler(ServerSocketChannel serverSocketChannel,Selector selector)
throws IOException {
/**
*如果是接入事件,创建socketChannel
*/
SocketChannel socketChannel = serverSocketChannel.accept();
/**
*将socketChannel设置为非阻塞工作模式
*/
socketChannel.configureBlocking(false);
/**
*将channel注册到selector上,监听可读事件
*/
socketChannel.register(selector, SelectionKey.OP_READ);
/**
* 回写客户端提示信息
*/
socketChannel.write(Charset.forName("UTF-8").
encode("你与聊天室的其他人都不是朋友关系,请注意隐私安全"));
}
/**
*可读事件处理
* @throws IOException
*/
private void readHandler(SelectionKey selectionKey,Selector selector) throws IOException {
/**
*要从 selectionKey中获取已经就绪的channe
*SocketChannel socketChannel = (SocketChannel)selectionKey.channel();
*/
SocketChannel socketChannel = (SocketChannel)selectionKey.channel();
/**
* 创建Buffer
*/
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
/**
*循环读取客户端信息
*/
String request = "";
while(socketChannel.read(byteBuffer)>0) {
/**
*切换buffer为读模式
*/
byteBuffer.flip();
/**
*读取buffer中的内容
*/
request += Charset.forName("UTF-8").decode(byteBuffer);
}
/**
* 再次将socketChannel注册到selector上
*/
socketChannel.register(selector, SelectionKey.OP_READ);
/**
* 将客户端发送的请求信息,广播给其他客户端
*/
if(request.length() > 0) {
broadCast(selector, socketChannel, request);
}
}
private void broadCast(Selector selector,SocketChannel sourceChannel,String request) {
/**
*获取到所有已接入的客户端channel
*/
Set selectionKeySet = selector.keys();
/**
*循环向所有channel广播
*/
selectionKeySet.forEach(selectionKey->{
Channel targetchannel = selectionKey.channel();
//剔除发消息的客户端
if(targetchannel instanceof SocketChannel
&& targetchannel != sourceChannel) {
try {
((SocketChannel)targetchannel).
write(Charset.forName("UTF-8").encode(request));
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
/**
*主方法
* @throws IOException
*/
public static void main(String[] args) throws IOException {
NIOServer server = new NIOServer();
server.start();
}
}
2、创建NIO客户端
package nio.study;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Scanner;
public class NioClient {
/**
*启动
* @throws IOException
*/
public void start(String nickName) throws IOException {
/**
*连接服务器端
*/
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8000));
/**
*接收服务端的响应
*/
//新开线程专门接收服务器端的响应数据
Selector selector = Selector.open();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
new Thread(new NioClientThreadHandler(selector)).start();;
/**
*向服务器发送数据
*/
System.out.println("客户端:");
Scanner scanner = new Scanner(System.in);
while(scanner.hasNextLine()) {
String request = scanner.nextLine();
if(request != null && request.length() > 0) {
socketChannel.write(Charset.forName("UTF-8").encode(nickName+":"+request));
}
}
}
/**
*主方法
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// new NioClient().start();
}
}
3、NIO客户端线程处理类
package nio.study;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;
public class NioClientThreadHandler implements Runnable {
private Selector selector;
public NioClientThreadHandler(Selector selector) {
super();
this.selector = selector;
}
@Override
public void run() {
for(;;) {
try {
int readyChannels = selector.select();
if(readyChannels == 0) continue;
/**
*获取channel可用集合
*/
Set selectedKeys = selector.selectedKeys();
Iterator iterator = selectedKeys.iterator();
while(iterator.hasNext()) {
/**
*selectrionKey实例
*/
SelectionKey selectionKey = iterator.next();
/**
*移除Set中的当前selectionKey
*/
iterator.remove();
/**
*如果是接入事件
*/
if(selectionKey.isReadable()) {
readHandler(selectionKey, selector);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void readHandler(SelectionKey selectionKey,Selector selector) throws IOException {
/**
*要从 selectionKey中获取已经就绪的channe
*SocketChannel socketChannel = (SocketChannel)selectionKey.channel();
*/
SocketChannel socketChannel = (SocketChannel)selectionKey.channel();
/**
* 创建Buffer
*/
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
/**
*循环读取客户端信息
*/
String response = "";
while(socketChannel.read(byteBuffer)>0) {
/**
*切换buffer为读模式
*/
byteBuffer.flip();
/**
*读取buffer中的内容
*/
response += Charset.forName("UTF-8").decode(byteBuffer);
}
/**
* 再次将socketChannel注册到selector上
*/
socketChannel.register(selector, SelectionKey.OP_READ);
/**
* 将服务的信息
*/
if(response.length() > 0) {
System.out.println(response);
}
}
}
4、创建NioClient多个客户端实现聊天
package nio.study;
import java.io.IOException;
public class AClient {
public static void main(String[] args) throws IOException {
new NioClient().start("AClient");
}
}
package nio.study;
import java.io.IOException;
public class BClient {
public static void main(String[] args) throws IOException {
new NioClient().start("BClient");
}
}
package nio.study;
import java.io.IOException;
public class CClient {
public static void main(String[] args) throws IOException {
new NioClient().start("CClient");
}
}