Netty入門——客戶端與服務端通訊

Netty簡介
Netty是一個基於JAVA NIO 類庫的異步通訊框架,它的架構特色是:異步非阻塞、基於事件驅動、高性能、高可靠性和高可定製性。換句話說,Netty是一個NIO框架,使用它能夠簡單快速地開發網絡應用程序,好比客戶端和服務端的協議。Netty大大簡化了網絡程序的開發過程好比TCP和UDP的 Socket的開發。Netty 已逐漸成爲 Java NIO 編程的首選框架。java

什麼是物聯網?
nio通訊框架編程

物聯網主要運用到netty哪些特性
a、TCP長鏈接
b、可以和各類序列化框架完美整合json

爲何要使用netty,相對於其餘通訊框架mina有哪些優勢
a、API使用簡單,開發門檻低
b、功能強大,預置了多種編解碼功能,支持多種主流協議
c、社區活躍,版本更新快
d、技術穩定可靠,如:elasticsearch、spark、dubbo、motan等開源框架底層通訊採用的是nettybootstrap

一、Netty服務端編寫
首先,Netty經過ServerBootstrap啓動服務端代碼,須要四步:
第一步,定義兩個線程組,用來處理客戶端通道的accept和讀寫事件
第二步,綁定服務端通道NioServerSocketChannel
第三步,給讀寫事件的線程通道綁定handle,處理具體的業務邏輯
第四步,綁定監聽
1.一、NettyServer——Netty服務端編寫服務器

import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.DelimiterBasedFrameDecoder; import io.netty.handler.codec.Delimiters; /** * Netty服務端編寫 * * @author Administrator * */
public class NettyServer { public static void main(String[] args) throws InterruptedException { // 首先,netty經過ServerBootstrap啓動服務端
        ServerBootstrap server = new ServerBootstrap(); EventLoopGroup parentGroup = new NioEventLoopGroup(); EventLoopGroup childGroup =new NioEventLoopGroup(); //第1步定義兩個線程組,用來處理客戶端通道的accept和讀寫事件 //parentGroup用來處理accept事件,childgroup用來處理通道的讀寫事件 //parentGroup獲取客戶端鏈接,鏈接接收到以後再將鏈接轉發給childgroup去處理
 server.group(parentGroup, childGroup); //用於構造服務端套接字ServerSocket對象,標識當服務器請求處理線程全滿時,用於臨時存放已完成三次握手的請求的隊列的最大長度。 //用來初始化服務端可鏈接隊列 //服務端處理客戶端鏈接請求是按順序處理的,因此同一時間只能處理一個客戶端鏈接,多個客戶端來的時候,服務端將不能處理的客戶端鏈接請求放在隊列中等待處理,backlog參數指定了隊列的大小。
        server.option(ChannelOption.SO_BACKLOG, 128); //第2步綁定服務端通道
        server.channel(NioServerSocketChannel.class); //第3步綁定handler,處理讀寫事件,ChannelInitializer是給通道初始化
        server.childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { //解碼器,接收的數據進行解碼,必定要加在SimpleServerHandler 的上面 //maxFrameLength表示這一貞最大的大小 //delimiter表示分隔符,咱們須要先將分割符寫入到ByteBuf中,而後當作參數傳入; //須要注意的是,netty並無提供一個DelimiterBasedFrameDecoder對應的編碼器實現(筆者沒有找到),所以在發送端須要自行編碼添加分隔符,如 \r \n分隔符
                ch.pipeline().addLast(new DelimiterBasedFrameDecoder(Integer.MAX_VALUE, Delimiters.lineDelimiter()[0])); //把傳過來的數據 轉換成byteBuf
                ch.pipeline().addLast(new SimpleServerHandler()); } }); //第4步綁定8080端口
        ChannelFuture future = server.bind(8080).sync(); //當通道關閉了,就繼續往下走
 future.channel().closeFuture().sync(); } }


1.二、SimpleServerHandler——處理客戶端返回的數據網絡

import java.nio.charset.Charset; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; /** * 處理客戶端返回的數據 * * @author Administrator * */
public class SimpleServerHandler extends ChannelInboundHandlerAdapter { /** * 讀取客戶端通道的數據 */ @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { //能夠在這裏面寫一套相似SpringMVC的框架 //讓SimpleServerHandler不跟任何業務有關,能夠封裝一套框架
        if(msg instanceof ByteBuf){ System.out.println(((ByteBuf)msg).toString(Charset.defaultCharset())); } //業務邏輯代碼處理框架。。。 //返回給客戶端的數據,告訴我已經讀到你的數據了
        String result = "hello client "; ByteBuf buf = Unpooled.buffer(); buf.writeBytes(result.getBytes()); ctx.channel().writeAndFlush(buf); ByteBuf buf2 = Unpooled.buffer(); buf2.writeBytes("\r\n".getBytes()); ctx.channel().writeAndFlush(buf2); System.out.println("=========="); } }

 

//使用下面命令測試上面代碼。
1.開啓上面main方法。
2.執行一下命令
c:>telnet localhost 8080
隨便輸入,會發現eclipse控制檯會監聽到輸入的內容,有個問題接收時一個字一個字接受,可讓他一行一行接收架構

二、netty客戶端編寫
第一步,鏈接到服務端
第二步,向服務端發送數據
第三步,處理服務端返回的數據
第四步,關閉鏈接
2.一、NettyClient——Netty客戶端編寫框架

import com.alibaba.fastjson.JSONObject; import com.dxfx.user.model.User; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.DelimiterBasedFrameDecoder; import io.netty.handler.codec.Delimiters; import io.netty.handler.codec.string.StringEncoder; import io.netty.util.AttributeKey; /** * Netty客戶端編寫 * @author Administrator * */
public class NettyClient { public static void main(String[] args) throws InterruptedException { // 首先,netty經過ServerBootstrap啓動服務端
        Bootstrap client = new Bootstrap(); //第1步 定義線程組,處理讀寫和連接事件,沒有了accept事件
        EventLoopGroup group = new NioEventLoopGroup(); client.group(group ); //第2步 綁定客戶端通道
        client.channel(NioSocketChannel.class); //第3步 給NIoSocketChannel初始化handler, 處理讀寫事件
        client.handler(new ChannelInitializer<NioSocketChannel>() {  //通道是NioSocketChannel
 @Override protected void initChannel(NioSocketChannel ch) throws Exception { //字符串編碼器,必定要加在SimpleClientHandler 的上面
                ch.pipeline().addLast(new StringEncoder()); ch.pipeline().addLast(new DelimiterBasedFrameDecoder( Integer.MAX_VALUE, Delimiters.lineDelimiter()[0])); //找到他的管道 增長他的handler
                ch.pipeline().addLast(new SimpleClientHandler()); } }); //鏈接服務器
        ChannelFuture future = client.connect("localhost", 8080).sync(); //發送數據給服務器
        User user = new User(); user.setAge(12); user.setId(1); user.setName("sssss"); future.channel().writeAndFlush(JSONObject.toJSONString(user)+"\r\n"); for(int i=0;i<5;i++){ String msg = "ssss"+i+"\r\n"; future.channel().writeAndFlush(msg); } //當通道關閉了,就繼續往下走
 future.channel().closeFuture().sync(); //接收服務端返回的數據
        AttributeKey<String> key = AttributeKey.valueOf("ServerData"); Object result = future.channel().attr(key).get(); System.out.println(result.toString()); } }

 

2.二、SimpleClientHandler——處理服務端返回的數據eclipse

import java.nio.charset.Charset; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.util.AttributeKey; /** * 處理服務端返回的數據 * * @author Administrator * */
public class SimpleClientHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof ByteBuf) { String value = ((ByteBuf) msg).toString(Charset.defaultCharset()); System.out.println("服務器端返回的數據:" + value); } AttributeKey<String> key = AttributeKey.valueOf("ServerData"); ctx.channel().attr(key).set("客戶端處理完畢"); //把客戶端的通道關閉
 ctx.channel().close(); } }

 

三、netty服務端輸出的信息異步

{"age":12,"id":1,"name":"sssss"} ========== ssss0 ========== ssss1 ========== ssss2 ========== ssss3 ========== ssss4 ==========

 

四、netty客戶端輸出的信息

服務器端返回的數據:hello client 
客戶端處理完畢
服務器端返回的數據:hello client 
服務器端返回的數據:hello client 
服務器端返回的數據:hello client 
服務器端返回的數據:hello client 
服務器端返回的數據:hello client 
相關文章
相關標籤/搜索