服务端:
服务器Server类
public class Server implements Runnable {
private int port;
private volatile boolean stop;
private Selector selector;
private ServerSocketChannel serverSocketChannel;
public Server(int port){
this.port = port;
}
public void init(){
try {
//打开一个选择器
selector = Selector.open();
//打开一个Server-Socket监听通道
serverSocketChannel = ServerSocketChannel.open();
//设置该通道为非阻塞模式
serverSocketChannel.configureBlocking(false);
//绑定端口
serverSocketChannel.socket().bind(new InetSocketAddress(port));
//将通道注册在选择器上面,并将准备连接状态作为通道订阅时间
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
stop = false;
System.out.println("服务器已经启动,端口号:" + port);
}catch (IOException e){
e.printStackTrace();
}
}
public void run() {
init();
while (!stop){
try {
//无论是否有读写事件发生,selector每隔1s被唤醒一次
selector.select(1000);
Set selectionKeys = selector.selectedKeys();
Iterator iterator = selectionKeys.iterator();
while (iterator.hasNext()){
SelectionKey selectionKey = iterator.next();
//判断是否准备好接收新进入的连接
if(selectionKey.isAcceptable()){
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
//通过ServerSocketChannel的accept()创建SocketChannel实例
//完成该操作意味着完成TCP三次握手,TCP物理链路正式建立
SocketChannel socketChannel = serverSocketChannel.accept();
//设置为非阻塞
socketChannel.configureBlocking(false);
//在选择器注册,并订阅读事件
socketChannel.register(selector,SelectionKey.OP_READ);
}
if(selectionKey.isReadable()){
SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
//创建byteBuffer,并开辟一个1M的缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
//读取请求码流,返回读取到的字节数
int readBytes = socketChannel.read(byteBuffer);
//判断客户端是否断开
if(readBytes < 0){
selectionKey.cancel();
socketChannel.close();
return;
}
//读取到字节,对字节进行编解码
if(readBytes>0){
//将缓冲区从写模式切换到读模式
byteBuffer.flip();
//根据缓冲区可读字节数创建字节数组
byte[] bytes = new byte[byteBuffer.remaining()];
//向缓冲区读数据到字节数组
byteBuffer.get(bytes);
String expression = new String(bytes,"UTF-8");
System.out.println("服务器收到消息:"+expression);
}
}
iterator.remove();
}
selectionKeys.clear();
}catch (IOException e){
e.printStackTrace();
}
}
//selector关闭后会自动释放里面管理的资源
if(selector != null){
try {
selector.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
客户端:
客户端Client类
public class Client implements Runnable {
private String host;
private int port;
private Selector selector;
private SocketChannel socketChannel;
private volatile boolean stop;
private String name;
public Client(int port,String name){
this("localhost",port,name);
}
public Client(String host,int port,String name){
this.host = host;
this.port = port;
this.name = name;
}
public void init(){
try {
//打开一个选择器
selector = Selector.open();
//打开一个Socket监听通道
socketChannel = SocketChannel.open();
//设置该通道为非阻塞模式
socketChannel.configureBlocking(false);
//在非阻塞模式下,该方法在建立连接之前就会返回结果了,后续为了确认连接是否建立成功,可以调用finishConnect()
socketChannel.connect(new InetSocketAddress(host,port));
//订阅连接事件
socketChannel.register(selector, SelectionKey.OP_CONNECT);
stop = false;
}catch (IOException e){
e.printStackTrace();
}
}
public void run() {
init();
int i = 0;
while (!stop){
try {
//无论是否有读写事件发生,selector每隔1s被唤醒一次
selector.select(1000);
Set selectionKeys = selector.selectedKeys();
Iterator iterator = selectionKeys.iterator();
while (iterator.hasNext()){
SelectionKey selectionKey = iterator.next();
//判断是否连接到服务器
if(selectionKey.isConnectable()){
//判断连接是否建立成功
if(socketChannel.finishConnect()){
sendMsg(name+" Connect Success!");
socketChannel.register(selector,SelectionKey.OP_WRITE);
}
}
if(selectionKey.isWritable()){
sendMsg(name+" is saying \"Hello World\"!"+i++);
Thread.sleep(1000);
}
iterator.remove();
}
selectionKeys.clear();
}catch (ConnectException e){
System.out.println("连接失败!");
return;
}catch (IOException e){
e.printStackTrace();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
public void sendMsg(String expression) throws IOException{
byte[] bytes = expression.getBytes();
ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
byteBuffer.put(bytes);
//翻转缓冲区,执行的操作:
//1.将limit的位置设为position之后的一个位置
//2.将position的位置重置为0
byteBuffer.flip();
socketChannel.write(byteBuffer);
//清空缓冲区
byteBuffer.clear();
}
}
测试过程:
测试类TestNio
public class TestNio {
public static void main(String[] args) {
Thread server = new Thread(new Server(10086));
Thread client1 = new Thread(new Client(10086,"ONE"));
Thread client2 = new Thread(new Client(10086,"TWO"));
server.start();
client1.start();
client2.start();
}
}
测试结果:
服务器已经启动,端口号:10086
服务器收到消息:TWO Connect Success!
服务器收到消息:ONE Connect Success!
服务器收到消息:ONE is saying "Hello World"!0
服务器收到消息:TWO is saying "Hello World"!0
服务器收到消息:ONE is saying "Hello World"!1
服务器收到消息:TWO is saying "Hello World"!1
服务器收到消息:ONE is saying "Hello World"!2
服务器收到消息:TWO is saying "Hello World"!2
服务器收到消息:ONE is saying "Hello World"!3
服务器收到消息:TWO is saying "Hello World"!3
服务器收到消息:ONE is saying "Hello World"!4
服务器收到消息:TWO is saying "Hello World"!4
服务器收到消息:ONE is saying "Hello World"!5
服务器收到消息:TWO is saying "Hello World"!5
服务器收到消息:ONE is saying "Hello World"!6
服务器收到消息:TWO is saying "Hello World"!6
服务器收到消息:ONE is saying "Hello World"!7
服务器收到消息:TWO is saying "Hello World"!7
服务器收到消息:ONE is saying "Hello World"!8
服务器收到消息:TWO is saying "Hello World"!8
服务器收到消息:ONE is saying "Hello World"!9
服务器收到消息:TWO is saying "Hello World"!9
服务器收到消息:ONE is saying "Hello World"!10
服务器收到消息:TWO is saying "Hello World"!10