日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

《精通并发与Netty》学习笔记(13 - 解决TCP粘包拆包(一)概念及实例演示)

發(fā)布時(shí)間:2025/6/17 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《精通并发与Netty》学习笔记(13 - 解决TCP粘包拆包(一)概念及实例演示) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、粘包/拆包概念

TCP是一個(gè)“流”協(xié)議,所謂流,就是沒有界限的一長(zhǎng)串二進(jìn)制數(shù)據(jù)。TCP作為傳輸層協(xié)議并不不了解上層業(yè)務(wù)數(shù)據(jù)的具體含義,它會(huì)根據(jù)TCP緩沖區(qū)的實(shí)際情況進(jìn)行數(shù)據(jù)包的劃分,所以在業(yè)務(wù)上認(rèn)為是一個(gè)完整的包,可能會(huì)被TCP拆分成多個(gè)包進(jìn)行發(fā)送,也有可能把多個(gè)小的包封裝成一個(gè)大的數(shù)據(jù)包發(fā)送,這就是所謂的TCP粘包和拆包問題。

一般所謂的TCP粘包是在一次接收數(shù)據(jù)不能完全地體現(xiàn)一個(gè)完整的消息數(shù)據(jù)。TCP通訊為何存在粘包呢?主要原因是TCP是以流的方式來(lái)處理數(shù)據(jù),再加上網(wǎng)絡(luò)上MTU的往往小于在應(yīng)用處理的消息數(shù)據(jù),所以就會(huì)引發(fā)一次接收的數(shù)據(jù)無(wú)法滿足消息的需要,導(dǎo)致粘包的存在。處理粘包的唯一方法就是制定應(yīng)用層的數(shù)據(jù)通訊協(xié)議,通過(guò)協(xié)議來(lái)規(guī)范現(xiàn)有接收的數(shù)據(jù)是否滿足消息數(shù)據(jù)的需要。?

現(xiàn)在假設(shè)客戶端向服務(wù)端連續(xù)發(fā)送了兩個(gè)數(shù)據(jù)包,用packet1和packet2來(lái)表示,那么服務(wù)端收到的數(shù)據(jù)可以分為三種,現(xiàn)列舉如下:?

第一種情況:

接收端正常收到兩個(gè)數(shù)據(jù)包,即沒有發(fā)生拆包和粘包的現(xiàn)象,此種情況不在本文的討論范圍內(nèi)。

?

第二種情況:

接收端只收到一個(gè)數(shù)據(jù)包,由于TCP是不會(huì)出現(xiàn)丟包的,所以這一個(gè)數(shù)據(jù)包中包含了發(fā)送端發(fā)送的兩個(gè)數(shù)據(jù)包的信息,這種現(xiàn)象即為粘包。這種情況由于接收端不知道這兩個(gè)數(shù)據(jù)包的界限,所以對(duì)于接收端來(lái)說(shuō)很難處理。

?

第三種情況:

這種情況有兩種表現(xiàn)形式,如下圖。接收端收到了兩個(gè)數(shù)據(jù)包,但是這兩個(gè)數(shù)據(jù)包要么是不完整的,要么就是多出來(lái)一塊,這種情況即發(fā)生了拆包和粘包。這兩種情況如果不加特殊處理,對(duì)于接收端同樣是不好處理的。

??

? ?

二、粘包問題的解決策略

  • 消息定長(zhǎng),報(bào)文大小固定長(zhǎng)度,不夠空格補(bǔ)全,發(fā)送和接收方遵循相同的約定,這樣即使粘包了通過(guò)接收方編程實(shí)現(xiàn)獲取定長(zhǎng)報(bào)文也能區(qū)分。
  • 包尾添加特殊分隔符,例如每條報(bào)文結(jié)束都添加回車換行符(例如FTP協(xié)議)或者指定特殊字符作為報(bào)文分隔符,接收方通過(guò)特殊分隔符切分報(bào)文區(qū)分。
  • 將消息分為消息頭和消息體,消息頭中包含表示信息的總長(zhǎng)度(或者消息體長(zhǎng)度)的字段

?三、Netty粘包和拆包解決方案

Netty提供了多個(gè)解碼器,可以進(jìn)行分包的操作,分別是:
LineBasedFrameDecoder
DelimiterBasedFrameDecoder(添加特殊分隔符報(bào)文來(lái)分包)
FixedLengthFrameDecoder(使用定長(zhǎng)的報(bào)文來(lái)分包)
LengthFieldBasedFrameDecoder

四、TCP粘包和拆包實(shí)例演示

首先編寫服務(wù)端

package com.spring.netty.handler;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 MyServer {public static void main(String[] args) throws Exception {EventLoopGroup bossGroup = new NioEventLoopGroup(1);EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap serverBootstrap = new ServerBootstrap();serverBootstrap.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).childHandler(new MyServerInitializer());ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();channelFuture.channel().closeFuture().sync();}finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}} }

?

package com.spring.netty.handler;import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel;public class MyServerInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new MyServerHandler());} }

?

package com.spring.netty.handler;import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler;import java.nio.charset.Charset; import java.util.UUID;public class MyServerHandler extends SimpleChannelInboundHandler<ByteBuf> {private int count;@Overrideprotected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {byte[] buffer = new byte[msg.readableBytes()];msg.readBytes(buffer);String message = new String(buffer, Charset.forName("utf-8"));System.out.println("服務(wù)端接收到的消息內(nèi)容:"+message);System.out.println("服務(wù)端接收的消息數(shù)量:"+(++this.count));ByteBuf responseByteBuf = Unpooled.copiedBuffer(UUID.randomUUID().toString(),Charset.forName("utf-8"));ctx.writeAndFlush(responseByteBuf);}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();} }

然后編寫客戶端

package com.spring.netty.handler;import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel;public class MyClient {public static void main(String[] args) throws Exception {EventLoopGroup eventLoopGroup = new NioEventLoopGroup();try {Bootstrap bootstrap = new Bootstrap();bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class).handler(new MyClientInitializer());ChannelFuture channelFuture = bootstrap.connect("localhost",8899).sync();channelFuture.channel().closeFuture().sync();}finally {eventLoopGroup.shutdownGracefully();}} }

?

package com.spring.netty.handler;import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel;public class MyClientInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new MyClientHandler());} }

?

package com.spring.netty.handler;import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.util.concurrent.EventExecutorGroup;import java.nio.charset.Charset;public class MyClientHandler extends SimpleChannelInboundHandler<ByteBuf> {private int count;@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception {for(int i=0;i<10;i++){ByteBuf buffer = Unpooled.copiedBuffer("send from client ", Charset.forName("utf-8"));ctx.writeAndFlush(buffer);}}@Overrideprotected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {byte[] buffer = new byte[msg.readableBytes()];msg.readBytes(buffer);String message = new String(buffer,Charset.forName("utf-8"));System.out.println("客戶端接收到的消息內(nèi)容:"+message);System.out.println("客戶端接收到的消息數(shù)量:"+(++this.count));}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {cause.printStackTrace();ctx.close();} }

分別運(yùn)行服務(wù)端和客戶端查看運(yùn)行效果

服務(wù)端效果:

客戶端效果:

本節(jié)我們介紹了TCP粘包拆包的現(xiàn)象及做了個(gè)實(shí)例演示,下節(jié)我們來(lái)介紹在Netty中如何解決粘包拆包問題。

轉(zhuǎn)載于:https://www.cnblogs.com/happy2010/p/10904121.html

總結(jié)

以上是生活随笔為你收集整理的《精通并发与Netty》学习笔记(13 - 解决TCP粘包拆包(一)概念及实例演示)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 性欧美巨大 | 真实的中国女人做爰 | 久久最新精品 | av成人免费观看 | 亚洲精品资源 | 在线一区二区三区视频 | 亚洲图片欧美色图 | 黑人干亚洲人 | 8x国产一区二区三区精品推荐 | 天天爱天天做天天爽 | 欧美熟妇7777一区二区 | 国产精品一区二区欧美 | 美国少妇在线观看免费 | 精品久久不卡 | 久久久无码人妻精品一区 | 懂色aⅴ国产一区二区三区 亚洲欧美国产另类 | 综合激情网五月 | 国产tv在线观看 | 成人在线毛片 | 欧美日韩精品一区二区三区 | 高潮毛片无遮挡高清免费 | 一区二区三区丝袜 | 国产青青 | 青娱乐在线播放 | 精品一区在线观看视频 | 久久久久久久国产精品毛片 | 伊人55 | 欧美资源在线观看 | 国产精品嫩草影院精东 | 亚洲天堂日本 | 日本最新中文字幕 | 翔田千里一区二区 | 欧美日韩你懂的 | 日韩高清免费av | 久久影 | 日韩精品在线一区 | 中文字幕欧美在线观看 | 日韩欧美在线视频免费观看 | 操操干干 | 在线 日本 制服 中文 欧美 | 国产精品资源在线观看 | 国产精品无码无卡无需播放器 | 久久综合成人网 | 亚洲免费资源 | 1024福利| 久久青青操 | 久久免费视频网站 | 黄色美女免费网站 | 日韩精品一区三区 | 精品久久久亚洲 | 午夜精品久久久久久久 | 美国特色黄a大片 | 99精品视频在线观看免费 | 五月婷婷在线播放 | 一区二区少妇 | 国产精品啊啊啊 | 国产一级大片在线观看 | 岛国免费视频 | 亚洲国产精品无码久久久久高潮 | 国产一级高清视频 | 午夜激情福利在线 | 国产女人与zoxxxx另类 | 欧美色图一区 | 亚洲天堂小视频 | 亚洲av电影一区二区 | 91蜜桃传媒精品久久久一区二区 | 亚洲一区二区中文字幕 | 亚洲精品免费播放 | 少妇又色又紧又爽又刺激视频 | 毛片av免费| 一亲二脱三插 | 亚洲一本二本 | 成人免费无码大片a毛片抽搐色欲 | 婷婷激情六月 | jizz毛片 | 免费的一级片 | 国产成人精品亚洲日本在线观看 | 天堂网视频在线观看 | 久久久午夜影院 | www.美色吧.com | 天天操人人 | www.av欧美 | 最新国产精品视频 | 欧美射图 | 别揉我奶头一区二区三区 | 欧美精品 在线观看 | 露脸丨91丨九色露脸 | 一级肉体全黄裸片 | 91小视频| 欧美一区二区日韩 | 中国黄色片视频 | 中文字幕人成乱码熟女香港 | 国产亚洲精品熟女国产成人 | 中日韩欧美在线观看 | 少妇一级淫片日本 | 后宫秀女调教(高h,np) | 黄色免费视频 | 欧美激情图片 | 亚洲精品电影院 |