nio,select,epoll,多路复用器
c10k问题
- 使用nio 可以利用同步非阻塞的形式获取进行socket交互,如下代码。
public static void main(String[] args) throws InterruptedException, IOException {
var clients = new LinkedList<SocketChannel>();
var ss = ServerSocketChannel.open(); //服务端开启监听:接受客户端
ss.bind(new InetSocketAddress(9090));
ss.configureBlocking(false); //重点 OS NONBLOCKING!!! //只让接受客户端 不阻塞
while (true) {
//接受客户端的连接
Thread.sleep(1000);
var client = ss.accept(); //不会阻塞? -1 NULL
//accept 调用内核了:1,没有客户端连接进来,返回值?在BIO 的时候一直卡着,但是在NIO ,不卡着,返回-1,NULL
//如果来客户端的连接,accept 返回的是这个客户端的fd 5,client object
//NONBLOCKING 就是代码能往下走了,只不过有不同的情况
if (client == null) {
// System.out.println("null.....");
} else {
client.configureBlocking(false); //重点 socket(服务端的listen socket<连接请求三次握手后,往我这里扔,我去通过accept 得到 连接的socket>,连接socket<连接后的数据读写使用的> )
int port = client.socket().getPort();
System.out.println("client..port: " + port);
clients.add(client);
}
var buffer = ByteBuffer.allocateDirect(4096); //可以在堆里 堆外
//遍历已经链接进来的客户端能不能读写数据
for (SocketChannel c : clients) { //串行化!!!! 多线程!!
int num = c.read(buffer); // >0 -1 0 //不会阻塞
if (num > 0) {
buffer.flip();
byte[] aaa = new byte[buffer.limit()];
buffer.get(aaa);
String b = new String(aaa);
System.out.println(c.socket().getPort() + " : " + b);
buffer.clear();
}
}
}
}
- 上述代码存在一个问题如果有10000个,client 每次循环时都得去check这1w个client 是否到达,性能消耗很大,这个时候可以使用多路复用器解决这个问题。
多路复用器
- 一次调用获取所有访问client进程的状态(可读不可读,可写不可写)
- 然后用程序读取需要读取的内容(如果不使用多路复用器则每次accept 都要去check 所有的状态)
多路复用器是1个线程
- 当多路复用器获取到数据后,需要进行的处理,会放到一个线程池里,让他运行。
对比
函数 | 特点 | 缺陷 |
---|---|---|
nio | 消耗的成本为用户态和内核态的切换,因为每次获取都去访问内核 | 和内核交互太频繁了 |
select/poll | 只向内核请求1次(请求时传递需要的所有描述符),内核返回所有 | 会造成On 时间复杂度的fds检索(当然肯定比nio 快) |
epoll | 通过回调的方式通知,而不是poll轮循 | - |
版权声明:
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自
幽林萌逐的blog!
喜欢就支持一下吧