传统Socket / OIO
1 public class OioServer { 2 3 @SuppressWarnings("resource") 4 public static void main(String[] args) throws Exception { 5 6 ExecutorService newCachedThreadPool = Executors.newCachedThreadPool(); 7 //创建socket服务,监听10101端口 8 ServerSocket server=new ServerSocket(10101); 9 System.out.println("服务器启动!"); 10 while(true){ 11 //获取一个套接字(阻塞) 12 final Socket socket = server.accept(); 13 System.out.println("来个一个新客户端!"); 14 newCachedThreadPool.execute(new Runnable() { 16 @Override 17 public void run() { 18 //业务处理 19 handler(socket); 20 } 21 }); 23 } 24 } 25 26 /** 27 * 读取数据 28 * @param socket 29 * @throws Exception 30 */ 31 public static void handler(Socket socket){ 32 try { 33 byte[] bytes = new byte[1024]; 34 InputStream inputStream = socket.getInputStream(); 35 36 while(true){ 37 //读取数据(阻塞) 38 int read = inputStream.read(bytes); 39 if(read != -1){ 40 System.out.println(new String(bytes, 0, read)); 41 }else{ 42 break; 43 } 44 } 45 } catch (Exception e) { 46 e.printStackTrace(); 47 }finally{ 48 try { 49 System.out.println("socket关闭"); 50 socket.close(); 51 } catch (IOException e) { 52 e.printStackTrace(); 53 } 54 } 55 } 56 }
缺点
单线程情况下只能有一个客户端
用线程池可以有多个客户端连接,但是非常消耗性能
类比图
NIOServer
public class NIOServer { 2 // 通道管理器 3 private Selector selector; 5 /** 6 * 获得一个ServerSocket通道,并对该通道做一些初始化的工作 7 * 8 * @param port 9 * 绑定的端口号 10 * @throws IOException 11 */ 12 public void initServer(int port) throws IOException { 13 // 获得一个ServerSocket通道 14 ServerSocketChannel serverChannel = ServerSocketChannel.open(); 15 // 设置通道为非阻塞 16 serverChannel.configureBlocking(false); 17 // 将该通道对应的ServerSocket绑定到port端口 18 serverChannel.socket().bind(new InetSocketAddress(port)); 19 // 获得一个通道管理器 20 this.selector = Selector.open(); 21 // 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后, 22 // 当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。 23 serverChannel.register(selector, SelectionKey.OP_ACCEPT); 24 } 25 26 /** 27 * 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理 28 * 29 * @throws IOException 30 */ 31 public void listen() throws IOException { 32 System.out.println("服务端启动成功!"); 33 // 轮询访问selector 34 while (true) { 35 // 当注册的事件到达时,方法返回;否则,该方法会一直阻塞 36 selector.select(); 37 // 获得selector中选中的项的迭代器,选中的项为注册的事件 38 Iterator
优点
利用Selector多路复用技术, 一个线程可以处理多个客户端.
类比图
Netty Server