最近一直在看与IM相关的东西说到这个java中应该要说到netty,下面来认识一下netty。 开始了解netty之前我们先了解下传统的IO编程。IO编程 我们来做一个比较简单的demo:客户端每隔5秒发送一条消息到服务端,服务端收到消息打印出来。服务端实现 Server端首先创建了一个serverSocket来监听8000端口,然后创建一个线程,线程里面不断调用阻塞方法serversocket。accept();获取新的连接,当获取到新的连接之后,给每条连接创建一个新的线程,这个线程负责从该连接中读取数据,然后读取数据是以字节流的方式。packagecom。pine。springbootdemo01。netty;importjava。io。IOException;importjava。io。InputStream;importjava。net。ServerSocket;importjava。net。Socket;authoranziyangversionV1。0date20223111:53上午publicclassIOServer{publicstaticvoidmain(String〔〕args)throwsException{ServerSocketserverSocketnewServerSocket(8000);接收新连接线程newThread((){while(true){try{阻塞方法获取新的连接SocketsocketserverSocket。accept();每一个新的连接都创建一个线程,负责读取数据newThread((){try{intlen;byte〔〕datanewbyte〔1024〕;InputStreaminputStreamsocket。getInputStream();按字节流方式读取数据while((leninputStream。read(data))!1){System。out。println(newString(data,0,len));}}catch(IOExceptione){System。err。println(e);}})。start();}catch(IOExceptione){System。err。println(e);}}})。start();}}客户端实现 启动一个线程连接到服务端,循环中每次睡眠五秒也就是每隔五秒发送一次消息。packagecom。pine。springbootdemo01。netty;importjava。io。IOException;importjava。net。Socket;importjava。util。Date;authoranziyangversionV1。0date20223111:54上午publicclassIOClient{publicstaticvoidmain(String〔〕args){启动一个线程newThread((){try{SocketsocketnewSocket(127。0。0。1,8000);while(true){try{socket。getOutputStream()。write((newDate():helloworldsocket)。getBytes());睡眠5秒Thread。sleep(5000);}catch(Exceptione){System。err。println(e);}}}catch(IOExceptione){System。err。println(e);}})。start();}} 先启动server端然后启动client可以看到server收到请求如下: 上面的demo,从服务端代码中我们可以看到,在传统的IO模型中,每个连接创建成功之后都需要一个线程来维护,每个线程包含一个whiletrue死循环,那么10w个连接对应10w个线程,继而10w个while死循环,这就带来如下几个问题:线程资源受限:线程是操作系统中非常宝贵的资源,同一时刻有大量的线程处于阻塞状态是非常严重的资源浪费,操作系统耗不起线程切换效率低下:单机CPU核数固定,线程爆炸之后操作系统频繁进行线程切换,应用性能急剧下降。除了以上两个问题,IO编程中,我们看到数据读写是以字节流为单位。 为了解决这三个问题,JDK在1。4之后提出了NIO。 NIO(NonblockingIO,在Java领域,也称为NewIO),是一种同步非阻塞的IO模型,也是IO多路复用的基础,已经被越来越多地应用到大型应用服务器,成为解决高并发与大量连接、IO处理问题的有效方式。 NIO编程 java对于非堵塞IO的支持是在2002年引入的,位于JDK1。4的java。nio包中。 IO和NIO的区别:IO是面向字节流和字符流的,而NIO是面向缓冲区的。IO是阻塞模式的,NIO是非阻塞模式的NIO新增了选择器的概念,可以通过选择器监听多个通道。 NIO用的是事件机制。它可以用一个线程把Accept,读,写操作,请求处理的逻辑全干了。如果什么事都没得做,它也不会死循环,它会将线程休眠起来,直到下一个事件来了再继续干活,这样的一个线程称之为NIO线程。 packagecom。pine。springbootdemo01。netty;importjava。io。IOException;importjava。net。InetSocketAddress;importjava。nio。ByteBuffer;importjava。nio。channels。SelectionKey;importjava。nio。channels。Selector;importjava。nio。channels。ServerSocketChannel;importjava。nio。channels。SocketChannel;importjava。nio。charset。Charset;importjava。util。Iterator;importjava。util。Set;authoranziyangversionV1。0date2022312:29下午publicclassNIOServer{publicstaticvoidmain(String〔〕args)throwsIOException{SelectorserverSelectorSelector。open();SelectorclientSelectorSelector。open();启动一个线程绑定select用于监听是否有新的连接newThread((){try{对应IO编程中服务端启动ServerSocketChannellistenerChannelServerSocketChannel。open();listenerChannel。socket()。bind(newInetSocketAddress(8000));listenerChannel。configureBlocking(false);listenerChannel。register(serverSelector,SelectionKey。OPACCEPT);while(true){监测是否有新的连接,这里的1指的是阻塞的时间为1msif(serverSelector。select(1)0){SetSelectionKeysetserverSelector。selectedKeys();IteratorSelectionKeykeyIteratorset。iterator();while(keyIterator。hasNext()){SelectionKeykeykeyIterator。next();if(key。isAcceptable()){try{(1)每来一个新连接,不需要创建一个线程,而是直接注册到clientSelectorSocketChannelclientChannel((ServerSocketChannel)key。channel())。accept();clientChannel。configureBlocking(false);clientChannel。register(clientSelector,SelectionKey。OPREAD);}finally{keyIterator。remove();}}}}}}catch(IOExceptione){System。err。println(e);}})。start();启动一个线程绑定select用于监听哪些连接有数据可读newThread((){try{while(true){(2)批量轮询是否有哪些连接有数据可读,这里的1指的是阻塞的时间为1msif(clientSelector。select(1)0){SetSelectionKeysetclientSelector。selectedKeys();IteratorSelectionKeykeyIteratorset。iterator();while(keyIterator。hasNext()){SelectionKeykeykeyIterator。next();if(key。isReadable()){try{SocketChannelclientChannel(SocketChannel)key。channel();ByteBufferbyteBufferByteBuffer。allocate(1024);(3)面向BufferclientChannel。read(byteBuffer);byteBuffer。flip();System。out。println(Charset。defaultCharset()。newDecoder()。decode(byteBuffer)。toString());}finally{keyIterator。remove();key。interestOps(SelectionKey。OPREAD);}}}}}}catch(IOExceptione){System。err。println(e);}})。start();}} 从上面的代码中我们可以看到NIO模型中通常会有两个线程,每个线程绑定一个轮询器selector,在我们这个例子中serverSelector负责轮询是否有新的连接,clientSelector负责轮询连接是否有数据可读服务端监测到新的连接之后,不再创建一个新的线程,而是直接将新连接绑定到clientSelector上,这样就不用IO模型中1w个while循环在死等,参见(1)clientSelector被一个while死循环包裹着,如果在某一时刻有多条连接有数据可读,那么通过clientSelector。select(1)方法可以轮询出来,进而批量处理,参见(2)数据的读写面向Buffer,参见(3) 启动NIOServermain方法然后启动之前的client可以看到控制打印 Netty编程 首先看下netty如何实现服务端的:packagecom。pine。springbootdemo01。netty;importio。netty。bootstrap。ServerBootstrap;importio。netty。channel。ChannelHandlerContext;importio。netty。channel。ChannelInitializer;importio。netty。channel。SimpleChannelInboundHandler;importio。netty。channel。nio。NioEventLoopGroup;importio。netty。channel。socket。nio。NioServerSocketChannel;importio。netty。channel。socket。nio。NioSocketChannel;importio。netty。handler。codec。string。StringDecoder;authoranziyangversionV1。0date2022312:41下午publicclassNettyServer{publicstaticvoidmain(String〔〕args){ServerBootstrapserverBootstrapnewServerBootstrap();NioEventLoopGroupbossnewNioEventLoopGroup();NioEventLoopGroupworkernewNioEventLoopGroup();serverBootstrap。group(boss,worker)。channel(NioServerSocketChannel。class)。childHandler(newChannelInitializerNioSocketChannel(){protectedvoidinitChannel(NioSocketChannelch){ch。pipeline()。addLast(newStringDecoder());ch。pipeline()。addLast(newSimpleChannelInboundHandlerString(){OverrideprotectedvoidchannelRead0(ChannelHandlerContextctx,Stringmsg){System。out。println(msg);}});}})。bind(8000);}} 上面代码明显比前面的NIO少很多代码,优雅了不少。 可以看到netty服务端输出内容: 本文就先聊这么多,主要是熟悉下netty编程,看下经典的helloworld。 感觉有收获点个赞,转发下哦 参考文档: https:juejin。cnbook6844733738119593991section6844733738270588942 https:www。jianshu。comp432d5557a19e https:www。cnblogs。comflyingeaglearticles11031163。html