場景
什么是Netty
Netty 是一個利用 Java 的高級網絡的能力,隱藏其背后的復雜性而提供一個易於使用的 API 的客戶端/服務器框架。
Netty 是基於 Java NIO 的異步事件驅動的網絡應用框架,使用 Netty 可以快速開發網絡應用,Netty 提供了高層次的抽象來簡化 TCP 和 UDP 服務器的編程,但是你仍然可以使用底層的 API。
Netty 的內部實現是很復雜的,但是 Netty 提供了簡單易用的API從網絡處理代碼中解耦業務邏輯。Netty 是完全基於 NIO 實現的,所以整個 Netty 都是異步的。
Netty 是最流行的 NIO 框架,它已經得到成百上千的商業、商用項目驗證,許多框架和開源組件的底層 rpc 都是使用的 Netty,如 Dubbo、Elasticsearch 等等。
這里使用IDEA和Gradle,也可以使用Maven作為依賴管理工具。
在Windows中下載配置以及在IDEA中配置Gradle參照如下
https://mp.csdn.net/console/editor/html/108578033
注:
博客:
https://blog.csdn.net/badao_liumang_qizhi
關注公眾號
霸道的程序猿
獲取編程相關電子書、教程推送與免費下載。
實現
IDEA新建一個Gradle項目
配置使用Java並設置JDK
新建之后的項目目錄
此時會自動在build.gradle類似於Maven的pom.xml中引入了junit的依賴。
這里需要引入Netty的依賴。
瀏覽器打開Maven中央倉庫地址
搜索netty-all
選擇穩定版本這里是4.1.52
選擇Gradle的依賴
將其復制進IDEA下的build.gradle中
dependencies { // https://mvnrepository.com/artifact/io.netty/netty-all compile group: 'io.netty', name: 'netty-all', version: '4.1.52.Final' }
因為上面已經設置了自動導入依賴。
所以保存后就能實現自動導入。
同樣在上面的gradle的配置的博客中設置了jar包的存儲位置。
來到配置的jar包的存儲位置就可以看到jar包所在的位置。
在項目中引入Netty后,在src下新建包,包下新建HelloWorldServer類作為服務端的啟動類
在啟動類中新建main方法
package com.badao.netty; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; public class HelloWorldServer { public static void main(String[] args) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try{ //服務端啟動類-Netty提供的啟動服務端的類 ServerBootstrap serverBootstrap = new ServerBootstrap(); //參數為兩個事件組 前面的用來接收請求 后面的用來處理 //childHandler 設置請求到了之后進行處理的處理器 serverBootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class) .childHandler(new HelloWorldServerInitializer()); //綁定端口 ChannelFuture channelFuture = serverBootstrap.bind(70).sync(); channelFuture.channel().closeFuture().sync(); }finally { //關閉事件組 bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } }
注意這里的都是引入的netty的包,不要引入nio的包。
首先EventLoopGroup是事件循環組,可以認為是一個死循環,一直監聽是否有連接然后處理。
這里使用兩個是Netty官方推薦,一個bossGroup只用來監聽連接,然后交由后面的workerGroup進行處理。
ServerBootstrap是Netty的啟動服務端的類。
分別設置兩個group並設置通道為NioServerSocketChannel
然后childHandler是設置對請求具體處理的處理器。這里新建了一個HelloWorldInititalizer類作為服務端初始化的類。
下面綁定了70端口。
所以在包下再新建類HelloWorldServerInitializer作為服務端初始化器,並使其繼承ChannelInitializer
然后重寫initChannel方法,連接一旦被創建后就會執行此方法。
package com.badao.netty; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.http.HttpServerCodec; //服務端初始化器 public class HelloWorldServerInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel ch) throws Exception { //連接一旦被創建后就會執行此方法 ChannelPipeline channelPipeline = ch.pipeline(); //在最后添加由Netty提供的處理器 channelPipeline.addLast("httpServerCodec",new HttpServerCodec()); channelPipeline.addLast("helloWorldServerHandler",new HelloWorldServerHandler()); } }
注意這里的繼承的泛型里面的SocketChannel是在netty包下的。
在方法中在處理的最后添加處理器,第一個添加的是Netty自帶的處理器。
后面再創建一個自定的處理器HelloWorldServerHandler
前面的name可以自己定義。
所以需要在包下再新建HelloWorldServerHandler處理器類並使其繼承SimpleChannelInboundHandler
然后重寫其方法channelRead0
此方法就是讀取客戶端發送過來的請求並返回響應。
package com.badao.netty; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.*; import io.netty.util.CharsetUtil; //自定義的處理器 public class HelloWorldServerHandler extends SimpleChannelInboundHandler<HttpObject> { //此方法就是讀取客戶端發送過來的請求並返回響應 @Override protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { if(msg instanceof HttpRequest) { //構造返回內容 ByteBuf content = Unpooled.copiedBuffer("公眾號:霸道的程序猿", CharsetUtil.UTF_8); //構造響應 FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,content); //設置響應頭類型 response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain"); //設置響應頭長度 response.headers().set(HttpHeaderNames.CONTENT_LENGTH,content.readableBytes()); //返回響應 ctx.writeAndFlush(response); } } }
在方法中構造返回的內容和響應頭,然后將其返回響應。
這樣一個客戶端,功能是接受到請求時返回字符串"公眾號:霸道的程序猿",就搭建完成了。
找到項目下的.idea下的gradle.xml,將下面的
<option name="delegatedBuild" value="false" />
改為false,如果沒有則將這行加上
這樣就能使用java運行main方法,gradle就不會認為其是task了。
運行最上面的服務端的main方法。
如果沒有輸出任何報錯則是運行成功。
怎樣去驗證服務端搭建成功?
這里可以使用curl去進行請求驗證
cURL是一個利用URL語法在命令行下工作的文件傳輸工具,1997年首次發行。
它支持文件上傳和下載,所以是綜合傳輸工具,但按傳統,習慣稱cURL為下載工具。
cURL還包含了用於程序開發的libcurl。
cURL支持的通信協議有FTP、FTPS、HTTP、HTTPS、TFTP、SFTP、Gopher、SCP、Telnet、DICT、FILE、LDAP、LDAPS、IMAP、POP3、SMTP和RTSP。
curl還支持SSL認證、HTTP POST、HTTP PUT、FTP上傳, HTTP form based upload、proxies、HTTP/2、cookies、用戶名+密碼認證(Basic, Plain, Digest, CRAM-MD5, NTLM, Negotiate and Kerberos)、file transfer resume、proxy tunneling。
這里因為是在Windows下,所以需要下載curl
下載地址:
這里下載64位的,將其解壓到磁盤上的某目錄。
找到其目錄下的bin目錄,即curl.exe所在的目錄。
在此處打開cmd
curl http://localhost:70