netty實戰之二 helloNetty
我們下面編寫四個類
1.用於接收資料的伺服器端Socket
2.用於接收客戶端的訊息,用於接收和反饋客戶端發出的訊息類ServertHandler
3.用於傳送資料的伺服器端Client
4.用於傳送資料和接收伺服器端發出的資料處理類ClientHandler
1.server類
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
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.string.StringDecoder;
public class Server {
public static void main(String[] args) throws InterruptedException {
//1.第一個執行緒組是用於接收Client端連線的
EventLoopGroup bossGroup = new NioEventLoopGroup();
//2.第二個執行緒組是用於實際的業務處理的
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup);//繫結兩個執行緒池
b.channel(NioServerSocketChannel.class);//指定NIO的模式,如果是客戶端就是NioSocketChannel
b.option(ChannelOption.SO_BACKLOG, 1024);//TCP的緩衝區設定
b.option(ChannelOption.SO_SNDBUF, 32*1024);//設定傳送緩衝的大小
b.option(ChannelOption.SO_RCVBUF, 32*1024);//設定接收緩衝區大小
b.option(ChannelOption.SO_KEEPALIVE, true);//保持連續
b.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());//拆包粘包定義結束字串(第一種解決方案)
sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,buf));//在管道中加入結束字串
// sc.pipeline().addLast(new FixedLengthFrameDecoder(200));第二種定長
sc.pipeline().addLast(new StringDecoder());//定義接收型別為字串把ByteBuf轉成String
sc.pipeline().addLast(new ServertHandler());//在這裡配置具體資料接收方法的處理
}
});
ChannelFuture future = b.bind(8765).sync();//繫結埠
future.channel().closeFuture().sync();//等待關閉(程式阻塞在這裡等待客戶端請求)
bossGroup.shutdownGracefully();//關閉執行緒
workerGroup.shutdownGracefully();//關閉執行緒
}
}
- 1在上面這個Server.java中,我們都要定義兩個執行緒池,boss和worker,boss是用於管理連線到server端的client的連線數的執行緒池,而woeker是用於管理實際操作的執行緒池。
- ServerBootstrap用一個ServerSocketChannelFactory 來例項化。ServerSocketChannelFactory 有兩種選擇,一種是NioServerSocketChannelFactory,一種是OioServerSocketChannelFactory。 前者使用NIO,後則使用普通的阻塞式IO。它們都需要兩個執行緒池例項作為引數來初始化,一個是boss執行緒池,一個是worker執行緒池。
- 然後使ServerBookstrap管理boss和worker執行緒池。並且設定各個緩衝區的大小。
- 這裡的事件處理類經常會被用來處理一個最近的已經接收的Channel。ChannelInitializer是一個特殊的處理類,他的目的是幫助使用者配置一個新的Channel。也許你想通過增加一些處理類比如NettyServerHandler來配置一個新的Channel 或者其對應的ChannelPipeline來實現你的網路程式。 當你的程式變的複雜時,可能你會增加更多的處理類到pipline上,然後提取這些匿名類到最頂層的類上。
- 在使用原始的encoder、decoder的情況下,Netty傳送接收資料都是按照ByteBuf的形式,其它形式都是不合法的。 而在上面這個Socket中,我使用
sc.pipeline().addLast()
這個方法設定了接收為字串型別,注意:只能設定接收為字串型別,傳送還是需要傳送ByteBuf型別的資料。而且在這裡我還設定了以$_為結尾的字串就代表了本次請求字串的結束。 - 通過
b.bind
繫結埠,用於監聽的埠號。
2.ServerHandler.java
public class ServertHandler extends ChannelHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
String body = (String) msg;
System.out.println("server"+body);//前面已經定義了接收為字串,這裡直接接收字串就可以
//服務端給客戶端的響應
String response= " hi client!$_";//傳送的資料以定義結束的字串結尾
ctx.writeAndFlush(Unpooled.copiedBuffer(response.getBytes()));//傳送必須還是ByteBuf型別
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
ServertHandler繼承自 ChannelHandlerAdapter,這個類實現了ChannelHandler介面,ChannelHandler提供了許多事件處理的介面方法,然後你可以覆蓋這些方法。現在僅僅只需要繼承ChannelHandlerAdapter類而不是你自己去實現介面方法。由於我們再server端開始的時候已經定義了接收型別為String,所以在這裡我們接收到的msg直接強轉成String就可以了。同時也要定義以什麼為一次請求的結尾。
3.Client.java
public class Client {
public static void main(String[] args) throws InterruptedException {
EventLoopGroup worker = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(worker)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel sc) throws Exception {
ByteBuf buf = Unpooled.copiedBuffer("$_".getBytes());
sc.pipeline().addLast(new DelimiterBasedFrameDecoder(1024,buf));
sc.pipeline().addLast(new StringDecoder());
sc.pipeline().addLast(new ClientHandler());
}
});
ChannelFuture f=b.connect("127.0.0.1",8765).sync();
f.channel().writeAndFlush(Unpooled.copiedBuffer(" hi server2$_".getBytes()));
f.channel().writeAndFlush(Unpooled.copiedBuffer(" hi server3$_".getBytes()));
f.channel().writeAndFlush(Unpooled.copiedBuffer(" hi server4$_".getBytes()));
f.channel().closeFuture().sync();
worker.shutdownGracefully();
}
}
client端和Socket端幾乎程式碼相同,只是client端用的不是ServerBootstrap而是Bootstrap來管理連線。這裡沒什麼好說的。
public class ClientHandler extends ChannelHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
System.out.println("client"+msg.toString());
} finally {
ReferenceCountUtil.release(msg);//釋放緩衝區
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
ClientHandler和ServertHandler程式碼和原理也是一樣,只是在client端我們要釋放緩衝區。為什麼在ServerHandler我們不需要釋放呢 ?因為在ServertHandler我們呼叫ctx.writeAndFlush
方法的時候,這個方法預設已經幫我們釋放了緩衝區。
相關文章
- netty實戰之一 認識nettyNetty
- Springboot 整合 Netty 實戰Spring BootNetty
- Flink的sink實戰之二:kafkaKafka
- client-go實戰之二:RESTClientclientGoREST
- OpenFaaS實戰之二:函式入門函式
- 《Netty實戰》-學習筆記1Netty筆記
- Kurento實戰之二:快速部署和體驗
- Flink處理函式實戰之二:ProcessFunction類函式Function
- yolov5實戰之二維碼檢測YOLO
- MyBatis初級實戰之二:增刪改查MyBatis
- Spring Cloud Gateway實戰之二:更多路由配置方式SpringCloudGateway路由
- elasticsearch實戰三部曲之二:文件操作Elasticsearch
- DL4J實戰之二:鳶尾花分類
- Netty高階應用及聊天室實戰Netty
- strimzi實戰之二:部署和訊息功能初體驗
- JavaCV的攝像頭實戰之二:本地視窗預覽Java
- spring4.1.8擴充套件實戰之二:Aware介面揭祕Spring套件
- CoProcessFunction實戰三部曲之二:狀態處理Function
- Netty網路聊天(一) 聊天室的實戰(最易懂)Netty
- Netty實戰:設計一個IM框架就這麼簡單!Netty框架
- Netty 實戰:如何編寫一個麻小俱全的 web 容器NettyWeb
- Netty FastThreadLocal 實踐NettyASTthread
- Strimzi Kafka Bridge(橋接)實戰之二:生產和傳送訊息Kafka橋接
- 自定義spring boot starter三部曲之二:實戰開發Spring Boot
- 網路應用扛把子Netty!騰訊高工手寫“Netty速成手冊”,3天帶你走向實戰Netty
- netty系列之:Bootstrap,ServerBootstrap和netty中的實現NettybootServer
- netty系列之:EventExecutor,EventExecutorGroup和netty中的實現Netty
- netty系列之:channel,ServerChannel和netty中的實現NettyServer
- Netty實現Web SocketNettyWeb
- Netty原始碼閱讀入門實戰(十一) - 設計模式的應用Netty原始碼設計模式
- netty系列之:EventLoop,EventLoopGroup和netty的預設實現NettyOOP
- Docker下RabbitMQ延時佇列實戰兩部曲之二:細說開發DockerMQ佇列
- Netty原始碼剖析與實戰-傅健-極客時間-返現24元Netty原始碼
- netty系列之:netty實現http2中的流控制NettyHTTP
- kubernetes實踐之二十六:GlusterFS
- kubernetes實踐之二十七:Harbor
- kubernetes實踐之二十:網路原理
- kubernetes實踐之二十二:Pod