NIO与Netty-2-BIO非阻塞改造
-
因为BIO是阻塞式IO,单线程情况下处理者线程可能阻塞在其中一个连接套接字的read或服务套接字的accept上,因此只能是针对每一个套接字,都新建一个线程处理其数据读取。
-
改造前BIO的模型
- 一个监听线程,多少连接就存在多少个连接线程。一个线程对应一个socket。
-
利用超时返回来改造
-
因为ServerSocket的accpet和连接socket的read有超时返回功能,可以利用此来进行(伪)非阻塞改造。
-
改造思路
-
只使用一个线程,在创建ServerSocket和Socket时设置上较短的超时时间,使得原本无数据就阻塞的accept和read都可以在超时时停止阻塞向下运行。
-
然后在死循环中先尝试accpet获取连接,再去挨个对建立的连接尝试进行read操作。
-
改造后的server
-
public static void main(String[] args) throws Exception { byte[] msg=new byte[1024];//存储收到信息用的数组 //存储建立好的连接和其输入流的map Map<Socket,InputStream> map=new HashMap<>(); //建立serversocket,并设置超时时间,防止一直阻塞 ServerSocket serverSocket = new ServerSocket(6666); serverSocket.setSoTimeout(1); System.out.println("服务器启动了"); while (true) {//一直轮询 try{ //accept若超时未获得新连接会抛出异常 Socket socket = serverSocket.accept(); System.out.println("连接到一个客户端"); socket.setSoTimeout(1);//设置超时时间 map.put(socket,socket.getInputStream()); }catch (SocketTimeoutException e){ //捕获超时异常不处理 } //将当前map的key拷贝下来 Set<Socket> clientSockets = new HashSet<>(map.keySet()); for(Socket socket1:clientSockets){//遍历已经建立的连接 try{ //read若超时未读到信息则抛出异常 int i = map.get(socket1).read(msg); if(i>0){//存在信息则 System.out.println("收到信息:"+ new String(msg).substring(0,i)); }else { map.get(socket1).close(); socket1.close(); map.remove(socket1); } }catch (SocketTimeoutException e){} catch (SocketException e){ map.get(socket1).close(); socket1.close(); map.remove(socket1); } } } }
-
此时我们的server只有一个线程,它可以处理多个socket。
-
-
-