package com.example.demo;
import com.example.demo.nio.Acceptor;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
@SpringBootTest
class DemoApplicationTests {
@Test
void contextLoads0() {
try {
Socket max = new Socket("localhost",9000);
OutputStream outputStream = max.getOutputStream();
outputStream.write("hello".getBytes());
outputStream.write("你好".getBytes());
max.close();
}catch (Exception e){
}
}
@Test
void contextLoads1() {
try {
int MESSAGE_LENGTH = 1024; // 消息长度
//是Java NIO库中的通道,用于监听和接受客户端连接
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//提供了非阻塞模式的支持,可以通过configureBlocking(false)方法设置为非阻塞模式。
serverSocketChannel.configureBlocking(false);
//绑定端口
serverSocketChannel.bind(new InetSocketAddress(9000));
//使用选择器(Selector)来管理多个通道,可以在一个线程中处理多个通道的连接请求。
Selector selector = Selector.open();
//通道注册到选择器中 返回令牌
SelectionKey register = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
//令牌挂载对象
register.attach(new Acceptor(selector,serverSocketChannel));
while (true) {
//选择一组键,其对应通道已准备好进行I/O操作。
//此方法执行阻塞选择操作。
//只有在至少选择了一个通道、调用了该选择器的唤醒方法或中断了当前线程(以先到者为准)后,它才会返回。
selector.select();
//获取选择器中所有令牌
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
//遍历
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
//是否已准备好接受新的套接字连接
if(key.isAcceptable()){
//获取令牌的挂载处理类 异步调用
Runnable runnable = (Runnable)key.attachment();
runnable.run();
}
if(key.isReadable()){
Runnable runnable = (Runnable)key.attachment();
runnable.run();
}
}
}
} catch (Exception e) {
}
}
}
package com.example.demo.nio;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
public class Acceptor implements Runnable{
ServerSocketChannel serverSocketChannel;
Selector selector;
public Acceptor(Selector selector, ServerSocketChannel serverSocketChannel){
this.selector=selector;
this.serverSocketChannel=serverSocketChannel;
}
@Override
public void run() {
//
try {
//接受与此通道的套接字的连接
System.out.println("进入Accept");
SocketChannel socketChannel = serverSocketChannel.accept();
System.out.println("有客户链接"+socketChannel.getRemoteAddress());
socketChannel.configureBlocking(false);
SelectionKey register = socketChannel.register(selector, SelectionKey.OP_READ);
register.attach(new WorkHandler(socketChannel));
System.out.println("离开Accept");
}catch (Exception e){}
}
}
package com.example.demo.nio;
import java.nio.ByteBuffer;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
public class WorkHandler implements Runnable {
SocketChannel socketChannel;
public WorkHandler( SocketChannel socketChannel){
this.socketChannel=socketChannel;
}
@Override
public void run() {
try {
System.out.println("进去WorkHandler");
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
socketChannel.read(byteBuffer);
String s = new String(byteBuffer.array(), StandardCharsets.UTF_8);
System.out.println("消息:::::::::::::::::::"+s);
//Thread.sleep(50000);
//socketChannel.write(ByteBuffer.wrap("你的消息我收到了".getBytes()));
System.out.println("离开WorkHandler");
} catch (Exception e) {
e.printStackTrace();
}
}
}