bio -> nio

一、概念

java.io ->bio或jio 阻塞io

nio -> new io 或non-blocking io 非阻塞io

二、BIO

java 1.4以前, io处理主要采用java.net(socket) 和java.io(io) 包中的类进行处理

1、以下是采用单线程方式进行通信

 1 package main.io.test;
 2 
 3 import java.net.ServerSocket;
 4 import java.net.Socket;
 5 import java.util.Scanner;
 6 
 7 public class BioServer {
 8     public static void main(String[] args) {
 9         try(ServerSocket serverSocket = new ServerSocket(8888)){
10             System.out.println(String.format("BioServer has started, listing on port:%s, currentThread:%s",serverSocket.getLocalSocketAddress(),Thread.currentThread().getName()));
11             while (true){
12                 Socket clientSocket = serverSocket.accept();
13                 System.out.println(String.format("Connection from ::%s, currentThread:%s",clientSocket.getRemoteSocketAddress(),Thread.currentThread().getName()));
14                 try(Scanner inputStream = new Scanner(clientSocket.getInputStream())){
15                      while(true){
16                          System.out.println(String.format("start get input from :%s,currentThread:%s",clientSocket.getRemoteSocketAddress(),Thread.currentThread().getName()));
17                          String request = inputStream.nextLine();
18                          System.out.println(String.format("end get input from :%s,currentThread:%s",clientSocket.getRemoteSocketAddress(),Thread.currentThread().getName()));
19                          if("quit".equalsIgnoreCase(request)){
20                              break;
21                          }
22                          System.out.println(String.format("From :%s  : %s, currentThread:%s",clientSocket.getRemoteSocketAddress(), request,Thread.currentThread().getName()));
23                          String response = "From BioServer Hello " + request + ".\n";
24                          clientSocket.getOutputStream().write(response.getBytes());
25                      }
26                 }catch (Exception e){
27                     e.printStackTrace();
28                 }
29             }
30         }catch (Exception e){
31            e.printStackTrace();
32         }
33     }
34 }

 第二个client连接不上的原因是,主线程一直在等待输入

 

扫描二维码关注公众号,回复: 6252171 查看本文章

 2、采用线程池的方式,来一个client,给其线程进行处理

 此处采用线程池而不采用手动new一个线程:

1)创建太多线程,服务器可能会崩掉

2)线程会抢夺cpu执行权,线程上线文的切换会浪费资源

 1 package main.io.test;
 2 
 3 import java.net.ServerSocket;
 4 import java.net.Socket;
 5 import java.util.concurrent.ExecutorService;
 6 import java.util.concurrent.Executors;
 7 
 8 public class BioThreadPoolServer {
 9     public static void main(String[] args) {
10         ExecutorService executorService = Executors.newFixedThreadPool(2);
11         RequestHandler requestHandler = new RequestHandler();
12         try(ServerSocket serverSocket = new ServerSocket(8888)){
13             System.out.println(String.format("BioThreadPoolServer has started, listing on port:%s, currentThread:%s",serverSocket.getLocalSocketAddress(),Thread.currentThread().getName()));
14             while (true){
15                 Socket clientSocket = serverSocket.accept();
16                 System.out.println("Connection from :"+ clientSocket.getRemoteSocketAddress() + "   currentThread:"+Thread.currentThread().getName());
17                 //采用线程池的方式
18                 executorService.submit(new ClientHandler(clientSocket, requestHandler));
19             }
20         }catch (Exception e){
21             e.printStackTrace();
22         }
23     }
24 }
 1 package main.io.test;
 2 
 3 import java.net.Socket;
 4 import java.util.Scanner;
 5 
 6 public class ClientHandler implements Runnable {
 7     Socket clientSocket;
 8     RequestHandler requestHandler;
 9     public ClientHandler(Socket clientSocket, RequestHandler requestHandler){
10         this.clientSocket = clientSocket;
11         this.requestHandler = requestHandler;
12     }
13     @Override
14     public void run() {
15         System.out.println("now start ClientHanler run ....,   currentThread:"+Thread.currentThread().getName());
16         try(Scanner inputStream = new Scanner(clientSocket.getInputStream())){
17             while(true){
18                 String request = inputStream.nextLine();
19                 if("quit".equalsIgnoreCase(request)){
20                     break;
21                 }
22                 System.out.println(String.format("From :%s  : %s, currentThread:%s",clientSocket.getRemoteSocketAddress(), request, Thread.currentThread().getName()));
23                 String response = "From BioServer Hello " + request + ".\n" + ",   currentThread:"+Thread.currentThread().getName();
24                 clientSocket.getOutputStream().write(response.getBytes());
25             }
26         }catch (Exception e){
27             e.printStackTrace();
28         }
29     }
30 }
1 package main.io.test;
2 
3 public class RequestHandler {
4     public void test(){
5         System.out.println("print test  is ok !");
6     }
7 }

 第一个client连接上后就打印出如下信息:

BioThreadPoolServer has started, listing on port:0.0.0.0/0.0.0.0:8888, currentThread:main
Connection from :/0:0:0:0:0:0:0:1:63981 currentThread:main
now start ClientHanler run ...., currentThread:pool-1-thread-1

一直可以连接上server的原因是,处理输入输出的一直是子线程, 主线程仍可以进行连接

 

 若中断第二个client,发现第三个client之前输入的打印了出来

三、NIO

java 1.4之后 java.nio

 1 package main.io.test;
 2 
 3 import java.io.IOException;
 4 import java.net.InetSocketAddress;
 5 import java.nio.ByteBuffer;
 6 import java.nio.channels.SelectionKey;
 7 import java.nio.channels.Selector;
 8 import java.nio.channels.ServerSocketChannel;
 9 import java.nio.channels.SocketChannel;
10 import java.util.Iterator;
11 import java.util.Set;
12 
13 public class NioServer {
14     public static void main(String[] args) throws IOException {
15         ServerSocketChannel serverChannel = ServerSocketChannel.open();
16         serverChannel.configureBlocking(false);
17         serverChannel.bind(new InetSocketAddress(9999));
18         System.out.println(String.format("NIO NioServer has started, listening to port:%s, currentThread:%s",serverChannel.getLocalAddress(), Thread.currentThread().getName()));
19         Selector selector = Selector.open();
20         serverChannel.register(selector, SelectionKey.OP_ACCEPT);
21         ByteBuffer buffer = ByteBuffer.allocate(1024);
22         RequestHandler requestHandler = new RequestHandler();
23         while (true){
24             //唯一一个会阻塞的地方,所有的等待都汇集于此
25             int select = selector.select();
26             if(select == 0){
27                 continue;
28             }
29 
30             Set<SelectionKey> selectionKeys = selector.selectedKeys();
31             Iterator<SelectionKey> iterator = selectionKeys.iterator();
32             while (iterator.hasNext()){
33                 SelectionKey key = iterator.next();
34                 if(key.isAcceptable()){
35                     ServerSocketChannel channel = (ServerSocketChannel) key.channel();
36                     SocketChannel clientChannel = channel.accept();
37                     System.out.println(String.format("Connection to from : %s, currentThread:%s",clientChannel.getRemoteAddress(), Thread.currentThread().getName()));
38                     clientChannel.configureBlocking(false);
39                     clientChannel.register(selector, SelectionKey.OP_READ);
40                 }
41 
42                 if(key.isReadable()){
43                     SocketChannel channel = (SocketChannel) key.channel();
44                     channel.read(buffer);
45                     String request = new String(buffer.array()).trim();
46                     System.out.println(String.format("From %s : request:%s, currentThread:%s", channel.getRemoteAddress(), request, Thread.currentThread().getName()));
47                     String response = requestHandler.test(request);
48                     channel.write(ByteBuffer.wrap(response.getBytes()));
49 
50                 }
51                 iterator.remove();
52             }
53         }
54     }
55 }

当然我们不必写NIO代码,目前Netty就是对NIO很好的封装和优化。

猜你喜欢

转载自www.cnblogs.com/dudu2mama/p/10877949.html
今日推荐