這篇文章給大家分享的是有關(guān)怎么使用Netty搭建服務(wù)端和客戶(hù)端的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過(guò)來(lái)看看吧。
成都創(chuàng)新互聯(lián)公司是一家專(zhuān)注于網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站設(shè)計(jì)與策劃設(shè)計(jì),許昌網(wǎng)站建設(shè)哪家好?成都創(chuàng)新互聯(lián)公司做網(wǎng)站,專(zhuān)注于網(wǎng)站建設(shè)十載,網(wǎng)設(shè)計(jì)領(lǐng)域的專(zhuān)業(yè)建站公司;建站業(yè)務(wù)涵蓋:許昌等地區(qū)。許昌做網(wǎng)站價(jià)格咨詢(xún):18980820575
服務(wù)端
public class PrintServer { public void bind(int port) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); //1 EventLoopGroup workerGroup = new NioEventLoopGroup(); //2 try { ServerBootstrap b = new ServerBootstrap(); //3 b.group(bossGroup, workerGroup) //4 .channel(NioServerSocketChannel.class) //5 .option(ChannelOption.SO_BACKLOG, 1024) //6 .childHandler(new ChannelInitializer<SocketChannel>() { //7 @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new PrintServerHandler()); } }); ChannelFuture f = b.bind(port).sync(); //8 f.channel().closeFuture().sync(); //9 } finally { // 優(yōu)雅退出,釋放線程池資源 bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { int port = 8080; new TimeServer().bind(port); } }
我們來(lái)分析一下上面的這段代碼(下面的每一點(diǎn)對(duì)應(yīng)上面的注釋?zhuān)?/p>
1~2:首先我們創(chuàng)建了兩個(gè)NioEventLoopGroup實(shí)例,它是一個(gè)由Netty封裝好的包含NIO的線程組。為什么創(chuàng)建兩個(gè)?我想經(jīng)過(guò)前面的學(xué)習(xí)大家應(yīng)該都清楚了。對(duì),因?yàn)镹etty的底層是IO多路復(fù)用,bossGroup 是用于接收客戶(hù)端的連接,原理就是一個(gè)實(shí)現(xiàn)的Selector的Reactor線程。而workerGroup用于進(jìn)行SocketChannel的網(wǎng)絡(luò)讀寫(xiě)。
3:創(chuàng)建一個(gè)ServerBootstrap對(duì)象,可以把它想象成Netty的入口,通過(guò)這類(lèi)來(lái)啟動(dòng)Netty,將所需要的參數(shù)傳遞到該類(lèi)當(dāng)中,大大降低了的開(kāi)發(fā)難度。
4:將兩個(gè)NioEventLoopGroup實(shí)例綁定到ServerBootstrap對(duì)象中。
5:創(chuàng)建Channel(典型的channel有NioSocketChannel,NioServerSocketChannel,OioSocketChannel,OioServerSocketChannel,EpollSocketChannel,EpollServerSocketChannel),這里創(chuàng)建的是NIOserverSocketChannel,它的功能可以理解為當(dāng)接受到客戶(hù)端的連接請(qǐng)求的時(shí)候,完成TCP三次握手,TCP物理鏈路建立成功。并將該“通道”與workerGroup線程組的某個(gè)線程相關(guān)聯(lián)。
6:設(shè)置參數(shù),這里設(shè)置的SO_BACKLOG,意思是客戶(hù)端連接等待隊(duì)列的長(zhǎng)度為1024.
7:建立連接后的具體Handler。就是我們接受數(shù)據(jù)后的具體操作,例如:記錄日志,對(duì)信息解碼編碼等。
8:綁定端口,同步等待成功
9:等待服務(wù)端監(jiān)聽(tīng)端口關(guān)閉
綁定該服務(wù)端的Handler
public class PrintServerHandler extends ChannelHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ByteBuf buf = (ByteBuf) msg; //1 byte[] req = new byte[buf.readableBytes()]; buf.readBytes(req); //將緩存區(qū)的字節(jié)數(shù)組復(fù)制到新建的req數(shù)組中 String body = new String(req, "UTF-8"); System.out.println(body); String response= "打印成功"; ByteBuf resp = Unpooled.copiedBuffer(response.getBytes()); ctx.write(resp); //2 } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); //3 } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { ctx.close(); } }
PrintServerHandler 繼承 ChannelHandlerAdapter ,在這里它的功能為 打印客戶(hù)端發(fā)來(lái)的數(shù)據(jù)并且返回客戶(hù)端打印成功。
我們只需要實(shí)現(xiàn)channelRead,exceptionCaught,前一個(gè)為接受消息具體邏輯的實(shí)現(xiàn),后一個(gè)為發(fā)生異常后的具體邏輯實(shí)現(xiàn)。
1:我們可以看到,接受的消息被封裝為了Object ,我們將其轉(zhuǎn)換為ByteBuf ,前一章的講解中也說(shuō)明了該類(lèi)的作用。我們需要讀取的數(shù)據(jù)就在該緩存類(lèi)中。
2~3:我們將寫(xiě)好的數(shù)據(jù)封裝到ByteBuf中,然后通過(guò)write方法寫(xiě)回到客戶(hù)端,這里的3調(diào)用flush方法的作用為,防止頻繁的發(fā)送數(shù)據(jù),write方法并不直接將數(shù)據(jù)寫(xiě)入SocketChannel中,而是把待發(fā)送的數(shù)據(jù)放到發(fā)送緩存數(shù)組中,再調(diào)用flush方法發(fā)送數(shù)據(jù)。
客戶(hù)端
public class PrintClient { public void connect(int port, String host) throws Exception { EventLoopGroup group = new NioEventLoopGroup(); //1 try { Bootstrap b = new Bootstrap(); //2 b.group(group) //3 .channel(NioSocketChannel.class) //4 .option(ChannelOption.TCP_NODELAY, true) //5 .handler(new ChannelInitializer<SocketChannel>() { //6 @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new PrintClientHandler()); } }); ChannelFuture f = b.connect(host, port).sync(); //7 f.channel().closeFuture().sync(); //8 } finally { // 優(yōu)雅退出,釋放NIO線程組 group.shutdownGracefully(); } } /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { int port = 8080; new TimeClient().connect(port, "127.0.0.1"); } }
我們繼續(xù)來(lái)分析一下上面的這段代碼(下面的每一點(diǎn)對(duì)應(yīng)上面的注釋?zhuān)?/p>
1:區(qū)別于服務(wù)端,我們?cè)诳蛻?hù)端只創(chuàng)建了一個(gè)NioEventLoopGroup實(shí)例,因?yàn)榭蛻?hù)端你并不需要使用I/O多路復(fù)用模型,需要有一個(gè)Reactor來(lái)接受請(qǐng)求。只需要單純的讀寫(xiě)數(shù)據(jù)即可
2:區(qū)別于服務(wù)端,我們?cè)诳蛻?hù)端只需要?jiǎng)?chuàng)建一個(gè)Bootstrap對(duì)象,它是客戶(hù)端輔助啟動(dòng)類(lèi),功能類(lèi)似于ServerBootstrap。
3:將NioEventLoopGroup實(shí)例綁定到Bootstrap對(duì)象中。
4:創(chuàng)建Channel(典型的channel有NioSocketChannel,NioServerSocketChannel,OioSocketChannel,OioServerSocketChannel,EpollSocketChannel,EpollServerSocketChannel),區(qū)別與服務(wù)端,這里創(chuàng)建的是NIOSocketChannel.
5:設(shè)置參數(shù),這里設(shè)置的TCP_NODELAY為true,意思是關(guān)閉延遲發(fā)送,一有消息就立即發(fā)送,默認(rèn)為false。
6:建立連接后的具體Handler。注意這里區(qū)別與服務(wù)端,使用的是handler()而不是childHandler()。handler和childHandler的區(qū)別在于,handler是接受或發(fā)送之前的執(zhí)行器;childHandler為建立連接之后的執(zhí)行器。
7:發(fā)起異步連接操作
8:當(dāng)代客戶(hù)端鏈路關(guān)閉
綁定該客戶(hù)端的Handler
public class PrintClientHandler extends ChannelHandlerAdapter { private static final Logger logger = Logger .getLogger(TimeClientHandler.class.getName()); private final ByteBuf firstMessage; /** * Creates a client-side handler. */ public TimeClientHandler() { byte[] req = "你好服務(wù)端".getBytes(); firstMessage = Unpooled.buffer(req.length); //1 firstMessage.writeBytes(req); } @Override public void channelActive(ChannelHandlerContext ctx) { ctx.writeAndFlush(firstMessage); //2 } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) //3 throws Exception { ByteBuf buf = (ByteBuf) msg; byte[] req = new byte[buf.readableBytes()]; buf.readBytes(req); String body = new String(req, "UTF-8"); System.out.println("服務(wù)端回應(yīng)消息 : " + body); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { //4 // 釋放資源 System.out.println("Unexpected exception from downstream : " + cause.getMessage()); ctx.close(); } }
PrintClientHandler 繼承 ChannelHandlerAdapter ,在這里它的功能為 發(fā)送數(shù)據(jù)并打印服務(wù)端發(fā)來(lái)的數(shù)據(jù)。
我們只需要實(shí)現(xiàn)channelActive,channelRead,exceptionCaught,第一個(gè)為建立連接后立即執(zhí)行,后兩個(gè)與一個(gè)為接受消息具體邏輯的實(shí)現(xiàn),另一個(gè)為發(fā)生異常后的具體邏輯實(shí)現(xiàn)。
1:將發(fā)送的信息封裝到ByteBuf中。
2:發(fā)送消息。
3:接受客戶(hù)端的消息并打印
4:發(fā)生異常時(shí),打印異常信息,釋放客戶(hù)端資源
感謝各位的閱讀!關(guān)于“怎么使用Netty搭建服務(wù)端和客戶(hù)端”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!
網(wǎng)頁(yè)題目:怎么使用Netty搭建服務(wù)端和客戶(hù)端
轉(zhuǎn)載來(lái)源:http://muchs.cn/article24/iepcje.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供全網(wǎng)營(yíng)銷(xiāo)推廣、Google、定制開(kāi)發(fā)、軟件開(kāi)發(fā)、做網(wǎng)站、外貿(mào)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)