纠纷奇闻社交美文家庭
投稿投诉
家庭城市
爱好生活
创业男女
能力餐饮
美文职业
心理周易
母婴奇趣
两性技能
社交传统
新闻范文
工作个人
思考社会
作文职场
家居中考
兴趣安全
解密魅力
奇闻笑话
写作笔记
阅读企业
饮食时事
纠纷案例
初中历史
说说童话
乐趣治疗

透过现象看本质,我找到了Netty粘包与半包的这几种解决方案

5月9日 呛人心投稿
  1、粘包与半包
  啥也不说了,直接上代码是不是有点不太友好,我所谓了,都快过年了,还要啥自行车
  我上来就是一段代码猛如虎1。1服务器代码publicclassStudyServer{staticfinalLoggerlogLoggerFactory。getLogger(StudyServer。class);voidstart(){NioEventLoopGroupbossnewNioEventLoopGroup(1);NioEventLoopGroupworkernewNioEventLoopGroup();try{ServerBootstrapserverBootstrapnewServerBootstrap();serverBootstrap。channel(NioServerSocketChannel。class);serverBootstrap。group(boss,worker);serverBootstrap。childHandler(newChannelInitializerSocketChannel(){OverrideprotectedvoidinitChannel(SocketChannelch){ch。pipeline()。addLast(newLoggingHandler(LogLevel。DEBUG));ch。pipeline()。addLast(newChannelInboundHandlerAdapter(){OverridepublicvoidchannelActive(ChannelHandlerContextctx)throwsException{连接建立时会执行该方法log。debug(connected{},ctx。channel());super。channelActive(ctx);}OverridepublicvoidchannelInactive(ChannelHandlerContextctx)throwsException{连接断开时会执行该方法log。debug(disconnect{},ctx。channel());super。channelInactive(ctx);}});}});ChannelFuturechannelFutureserverBootstrap。bind(8080);log。debug({}binding。。。,channelFuture。channel());channelFuture。sync();log。debug({}bound。。。,channelFuture。channel());关闭channelchannelFuture。channel()。closeFuture()。sync();}catch(InterruptedExceptione){log。error(servererror,e);}finally{boss。shutdownGracefully();worker。shutdownGracefully();log。debug(stopped);}}publicstaticvoidmain(String〔〕args){newStudyServer()。start();}}1。2粘包现象
  客户端代码publicclassStudyClient{staticfinalLoggerlogLoggerFactory。getLogger(StudyClient。class);publicstaticvoidmain(String〔〕args){NioEventLoopGroupworkernewNioEventLoopGroup();try{BootstrapbootstrapnewBootstrap();bootstrap。channel(NioSocketChannel。class);bootstrap。group(worker);bootstrap。handler(newChannelInitializerSocketChannel(){OverrideprotectedvoidinitChannel(SocketChannelch)throwsException{log。debug(connected。。。);ch。pipeline()。addLast(newChannelInboundHandlerAdapter(){OverridepublicvoidchannelActive(ChannelHandlerContextctx)throwsException{log。debug(sending。。。);每次发送16个字节的数据,共发送10次for(inti0;i10;i){ByteBufbufferctx。alloc()。buffer();buffer。writeBytes(newbyte〔〕{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15});ctx。writeAndFlush(buffer);}}});}});ChannelFuturechannelFuturebootstrap。connect(127。0。0。1,8080)。sync();channelFuture。channel()。closeFuture()。sync();}catch(InterruptedExceptione){log。error(clienterror,e);}finally{worker。shutdownGracefully();}}}
  服务器接收结果7999〔nioEventLoopGroup31〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0x5b43ecb0,L:127。0。0。1:8080R:127。0。0。1:53797〕READ:160B0123456789abcdef00000000000102030405060708090a0b0c0d0e0f。。。。。。。。。。。。。。。。00000010000102030405060708090a0b0c0d0e0f。。。。。。。。。。。。。。。。00000020000102030405060708090a0b0c0d0e0f。。。。。。。。。。。。。。。。00000030000102030405060708090a0b0c0d0e0f。。。。。。。。。。。。。。。。00000040000102030405060708090a0b0c0d0e0f。。。。。。。。。。。。。。。。00000050000102030405060708090a0b0c0d0e0f。。。。。。。。。。。。。。。。00000060000102030405060708090a0b0c0d0e0f。。。。。。。。。。。。。。。。00000070000102030405060708090a0b0c0d0e0f。。。。。。。。。。。。。。。。00000080000102030405060708090a0b0c0d0e0f。。。。。。。。。。。。。。。。00000090000102030405060708090a0b0c0d0e0f。。。。。。。。。。。。。。。。
  可见虽然客户端是分别以16字节为单位,通过channel向服务器发送了10次数据,可是服务器端却只接收了一次,接收数据的大小为160B,即客户端发送的数据总大小,这就是粘包现象1。3半包现象
  将客户端服务器之间的channel容量进行调整
  服务器代码调整channel的容量serverBootstrap。option(ChannelOption。SORCVBUF,10);
  注意
  serverBootstrap。option(ChannelOption。SORCVBUF,10)影响的底层接收缓冲区(即滑动窗口)大小,仅决定了netty读取的最小单位,netty实际每次读取的一般是它的整数倍
  服务器接收结果5901〔nioEventLoopGroup31〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0xc73284f3,L:127。0。0。1:8080R:127。0。0。1:49679〕READ:36B0123456789abcdef00000000000102030405060708090a0b0c0d0e0f。。。。。。。。。。。。。。。。00000010000102030405060708090a0b0c0d0e0f。。。。。。。。。。。。。。。。0000002000010203。。。。5901〔nioEventLoopGroup31〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0xc73284f3,L:127。0。0。1:8080R:127。0。0。1:49679〕READ:40B0123456789abcdef000000000405060708090a0b0c0d0e0f00010203。。。。。。。。。。。。。。。。000000100405060708090a0b0c0d0e0f00010203。。。。。。。。。。。。。。。。000000200405060708090a0b。。。。。。。。5901〔nioEventLoopGroup31〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0xc73284f3,L:127。0。0。1:8080R:127。0。0。1:49679〕READ:40B0123456789abcdef000000000c0d0e0f000102030405060708090a0b。。。。。。。。。。。。。。。。000000100c0d0e0f000102030405060708090a0b。。。。。。。。。。。。。。。。000000200c0d0e0f00010203。。。。。。。。5901〔nioEventLoopGroup31〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0xc73284f3,L:127。0。0。1:8080R:127。0。0。1:49679〕READ:40B0123456789abcdef000000000405060708090a0b0c0d0e0f00010203。。。。。。。。。。。。。。。。000000100405060708090a0b0c0d0e0f00010203。。。。。。。。。。。。。。。。000000200405060708090a0b。。。。。。。。5901〔nioEventLoopGroup31〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0xc73284f3,L:127。0。0。1:8080R:127。0。0。1:49679〕READ:4B0123456789abcdef000000000c0d0e0f。。。。
  可见客户端每次发送的数据,因channel容量不足,无法将发送的数据一次性接收,便产生了半包现象1。4现象分析1。4。1粘包现象发送abcdef,接收abcdef原因应用层接收方ByteBuf设置太大(Netty默认1024);接收方缓冲数据,一起发送传输层网络层滑动窗口:假设发送方256bytes表示一个完整报文,但由于接收方处理不及时且窗口大小足够大(大于256bytes),这256bytes字节就会缓冲在接收方的滑动窗口中,当滑动窗口中缓冲了多个报文就会粘包Nagle算法:会造成粘包1。4。2半包现象发送abcdef,接收abcdef原因应用层接收方ByteBuf小于实际发送数据量传输层网络层滑动窗口:假设接收方的窗口只剩了128bytes,发送方的报文大小是256bytes,这时接收方窗口中无法容纳发送方的全部报文,发送方只能先发送前128bytes,等待ack后才能发送剩余部分,这就造成了半包数据链路层MSS限制:当发送的数据超过MSS限制后,会将数据切分发送,就会造成半包1。4。3本质
  发生粘包与半包现象的本质是因为TCP是流式协议,消息无边界1。5解决方案1。5。1短链接
  客户端每次向服务器发送数据以后,就与服务器断开连接,此时的消息边界为连接建立到连接断开。这时便无需使用滑动窗口等技术来缓冲数据,则不会发生粘包现象。但如果一次性数据发送过多,接收方无法一次性容纳所有数据,还是会发生半包现象,所以短链接无法解决半包现象
  客户端代码改进
  修改channelActive方法publicvoidchannelActive(ChannelHandlerContextctx)throwsException{log。debug(sending。。。);ByteBufbufferctx。alloc()。buffer(16);buffer。writeBytes(newbyte〔〕{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15});ctx。writeAndFlush(buffer);使用短链接,每次发送完毕后就断开连接ctx。channel()。close();}
  将发送步骤整体封装为send()方法,调用10次send()方法,模拟发送10次数据publicstaticvoidmain(String〔〕args){发送10次for(inti0;i10;i){send();}}
  运行结果6452〔nioEventLoopGroup31〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0x3eb6a684,L:127。0。0。1:8080R:127。0。0。1:65024〕ACTIVE6468〔nioEventLoopGroup31〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0x3eb6a684,L:127。0。0。1:8080R:127。0。0。1:65024〕READ:16B0123456789abcdef00000000000102030405060708090a0b0c0d0e0f。。。。。。。。。。。。。。。。6468〔nioEventLoopGroup31〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0x3eb6a684,L:127。0。0。1:8080!R:127。0。0。1:65024〕INACTIVE6483〔nioEventLoopGroup32〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0x7dcc31ff,L:127。0。0。1:8080R:127。0。0。1:65057〕ACTIVE6483〔nioEventLoopGroup32〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0x7dcc31ff,L:127。0。0。1:8080R:127。0。0。1:65057〕READ:16B0123456789abcdef00000000000102030405060708090a0b0c0d0e0f。。。。。。。。。。。。。。。。6483〔nioEventLoopGroup32〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0x7dcc31ff,L:127。0。0。1:8080!R:127。0。0。1:65057〕INACTIVE。。。
  客户端先于服务器建立连接,此时控制台打印ACTIVE,之后客户端向服务器发送了16B的数据,发送后断开连接,此时控制台打印INACTIVE,可见未出现粘包现象1。5。2定长解码器
  客户端于服务器约定一个最大长度,保证客户端每次发送的数据长度都不会大于该长度。若发送数据长度不足则需要补齐至该长度
  服务器接收数据时,将接收到的数据按照约定的最大长度进行拆分,即使发送过程中产生了粘包,也可以通过定长解码器将数据正确地进行拆分。服务端需要用到FixedLengthFrameDecoder对数据进行定长解码,具体使用方法如下ch。pipeline()。addLast(newFixedLengthFrameDecoder(16));
  客户端代码
  客户端发送数据的代码如下约定最大长度为16finalintmaxLength16;被发送的数据向服务器发送10个报文for(inti0;i10;i){ByteBufbufferctx。alloc()。buffer(maxLength);定长byte数组,未使用部分会以0进行填充byte〔〕bytesnewbyte〔maxLength〕;生成长度为015的数据for(intj0;j(int)(Math。random()(maxLength1));j){bytes〔j〕(byte)c;}buffer。writeBytes(bytes);c;将数据发送给服务器ctx。writeAndFlush(buffer);}
  服务器代码
  使用FixedLengthFrameDecoder对粘包数据进行拆分,该handler需要添加在LoggingHandler之前,保证数据被打印时已被拆分通过定长解码器对粘包数据进行拆分ch。pipeline()。addLast(newFixedLengthFrameDecoder(16));ch。pipeline()。addLast(newLoggingHandler(LogLevel。DEBUG));
  运行结果8222〔nioEventLoopGroup31〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0xbc122d07,L:127。0。0。1:8080R:127。0。0。1:52954〕READ:16B0123456789abcdef0000000061616161000000000000000000000000aaaa。。。。。。。。。。。。8222〔nioEventLoopGroup31〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0xbc122d07,L:127。0。0。1:8080R:127。0。0。1:52954〕READ:16B0123456789abcdef0000000062626200000000000000000000000000bbb。。。。。。。。。。。。。8222〔nioEventLoopGroup31〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0xbc122d07,L:127。0。0。1:8080R:127。0。0。1:52954〕READ:16B0123456789abcdef0000000063630000000000000000000000000000cc。。。。。。。。。。。。。。。。。1。5。3行解码器
  行解码器的是通过分隔符对数据进行拆分来解决粘包半包问题的
  可以通过LineBasedFrameDecoder(intmaxLength)来拆分以换行符()为分隔符的数据,也可以通过DelimiterBasedFrameDecoder(intmaxFrameLength,ByteBuf。。。delimiters)来指定通过什么分隔符来拆分数据(可以传入多个分隔符)
  两种解码器都需要传入数据的最大长度,若超出最大长度,会抛出TooLongFrameException异常
  以换行符为分隔符
  客户端代码约定最大长度为64finalintmaxLength64;被发送的数据for(inti0;i10;i){ByteBufbufferctx。alloc()。buffer(maxLength);生成长度为062的数据RandomrandomnewRandom();StringBuildersbnewStringBuilder();for(intj0;j(int)(random。nextInt(maxLength2));j){sb。append(c);}数据以结尾sb。append();buffer。writeBytes(sb。toString()。getBytes(StandardCharsets。UTF8));c;将数据发送给服务器ctx。writeAndFlush(buffer);}
  服务器代码通过行解码器对粘包数据进行拆分,以为分隔符需要指定最大长度ch。pipeline()。addLast(newDelimiterBasedFrameDecoder(64));ch。pipeline()。addLast(newLoggingHandler(LogLevel。DEBUG));
  运行结果4184〔nioEventLoopGroup31〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0x9d6ac701,L:127。0。0。1:8080R:127。0。0。1:58282〕READ:10B0123456789abcdef0000000061616161616161616161aaaaaaaaaa4184〔nioEventLoopGroup31〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0x9d6ac701,L:127。0。0。1:8080R:127。0。0。1:58282〕READ:11B0123456789abcdef000000006262626262626262626262bbbbbbbbbbb4184〔nioEventLoopGroup31〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0x9d6ac701,L:127。0。0。1:8080R:127。0。0。1:58282〕READ:2B0123456789abcdef000000006363cc。。。
  以自定义分隔符c为分隔符
  客户端代码。。。数据以c结尾sb。append(c);buffer。writeBytes(sb。toString()。getBytes(StandardCharsets。UTF8));。。。
  服务器代码将分隔符放入ByteBuf中ByteBufbufSetch。alloc()。buffer()。writeBytes(c。getBytes(StandardCharsets。UTF8));通过行解码器对粘包数据进行拆分,以c为分隔符ch。pipeline()。addLast(newDelimiterBasedFrameDecoder(64,ch。alloc()。buffer()。writeBytes(bufSet)));ch。pipeline()。addLast(newLoggingHandler(LogLevel。DEBUG));
  运行结果8246〔nioEventLoopGroup31〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0x86215ccd,L:127。0。0。1:8080R:127。0。0。1:65159〕READ:14B0123456789abcdef000000006161616161616161616161616161aaaaaaaaaaaaaa8247〔nioEventLoopGroup31〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0x86215ccd,L:127。0。0。1:8080R:127。0。0。1:65159〕READ:3B0123456789abcdef00000000626262bbb。。。1。5。4长度字段解码器
  在传送数据时可以在数据中添加一个用于表示有用数据长度的字段,在解码时读取出这个用于表明长度的字段,同时读取其他相关参数,即可知道最终需要的数据是什么样子的
  LengthFieldBasedFrameDecoder解码器可以提供更为丰富的拆分方法,其构造方法有五个参数publicLengthFieldBasedFrameDecoder(intmaxFrameLength,intlengthFieldOffset,intlengthFieldLength,intlengthAdjustment,intinitialBytesToStrip)
  参数解析maxFrameLength数据最大长度表示数据的最大长度(包括附加信息、长度标识等内容)lengthFieldOffset数据长度标识的起始偏移量用于指明数据第几个字节开始是用于标识有用字节长度的,因为前面可能还有其他附加信息lengthFieldLength数据长度标识所占字节数(用于指明有用数据的长度)数据中用于表示有用数据长度的标识所占的字节数lengthAdjustment长度表示与有用数据的偏移量用于指明数据长度标识和有用数据之间的距离,因为两者之间还可能有附加信息initialBytesToStrip数据读取起点读取起点,不读取0initialBytesToStrip之间的数据
  参数图解
  lengthFieldOffset0lengthFieldLength2lengthAdjustment0initialBytesToStrip0(donotstripheader)BEFOREDECODE(14bytes)AFTERDECODE(14bytes)LengthActualContentLengthActualContent0x000CHELLO,WORLD0x000CHELLO,WORLD
  从0开始即为长度标识,长度标识长度为2个字节
  0x000C即为后面HELLO,WORLD的长度lengthFieldOffset0lengthFieldLength2lengthAdjustment0initialBytesToStrip2(thelengthoftheLengthfield)BEFOREDECODE(14bytes)AFTERDECODE(12bytes)LengthActualContentActualContent0x000CHELLO,WORLDHELLO,WORLD
  从0开始即为长度标识,长度标识长度为2个字节,读取时从第二个字节开始读取(此处即跳过长度标识)
  因为跳过了用于表示长度的2个字节,所以此处直接读取HELLO,WORLDlengthFieldOffset2(thelengthofHeader1)lengthFieldLength3lengthAdjustment0initialBytesToStrip0BEFOREDECODE(17bytes)AFTERDECODE(17bytes)Header1LengthActualContentHeader1LengthActualContent0xCAFE0x00000CHELLO,WORLD0xCAFE0x00000CHELLO,WORLD
  长度标识前面还有2个字节的其他内容(0xCAFE),第三个字节开始才是长度标识,长度表示长度为3个字节(0x00000C)
  Header1中有附加信息,读取长度标识时需要跳过这些附加信息来获取长度lengthFieldOffset0lengthFieldLength3lengthAdjustment2(thelengthofHeader1)initialBytesToStrip0BEFOREDECODE(17bytes)AFTERDECODE(17bytes)LengthHeader1ActualContentLengthHeader1ActualContent0x00000C0xCAFEHELLO,WORLD0x00000C0xCAFEHELLO,WORLD
  从0开始即为长度标识,长度标识长度为3个字节,长度标识之后还有2个字节的其他内容(0xCAFE)
  长度标识(0x00000C)表示的是从其后lengthAdjustment(2个字节)开始的数据的长度,即HELLO,WORLD,不包括0xCAFElengthFieldOffset1(thelengthofHDR1)lengthFieldLength2lengthAdjustment1(thelengthofHDR2)initialBytesToStrip3(thelengthofHDR1LEN)BEFOREDECODE(16bytes)AFTERDECODE(13bytes)HDR1LengthHDR2ActualContentHDR2ActualContent0xCA0x000C0xFEHELLO,WORLD0xFEHELLO,WORLD
  长度标识前面有1个字节的其他内容,后面也有1个字节的其他内容,读取时从长度标识之后3个字节处开始读取,即读取0xFEHELLO,WORLD
  使用
  通过EmbeddedChannel对handler进行测试publicclassEncoderStudy{publicstaticvoidmain(String〔〕args){模拟服务器使用EmbeddedChannel测试handlerEmbeddedChannelchannelnewEmbeddedChannel(数据最大长度为1KB,长度标识前后各有1个字节的附加信息,长度标识长度为4个字节(int)newLengthFieldBasedFrameDecoder(1024,1,4,1,0),newLoggingHandler(LogLevel。DEBUG));模拟客户端,写入数据ByteBufbufferByteBufAllocator。DEFAULT。buffer();send(buffer,Hello);channel。writeInbound(buffer);send(buffer,World);channel。writeInbound(buffer);}privatestaticvoidsend(ByteBufbuf,Stringmsg){得到数据的长度intlengthmsg。length();byte〔〕bytesmsg。getBytes(StandardCharsets。UTF8);将数据信息写入buf写入长度标识前的其他信息buf。writeByte(0xCA);写入数据长度标识buf。writeInt(length);写入长度标识后的其他信息buf。writeByte(0xFE);写入具体的数据buf。writeBytes(bytes);}}
  运行结果146〔main〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0xembedded,L:embeddedR:embedded〕READ:11B0123456789abcdef00000000ca00000005fe48656c6c6f。。。。。。Hello146〔main〕DEBUGio。netty。handler。logging。LoggingHandler〔id:0xembedded,L:embeddedR:embedded〕READ:11B0123456789abcdef00000000ca00000005fe576f726c64。。。。。。World
  作者:博学谷
  链接:https:juejin。cnpost7185044730512670781
投诉 评论

透过现象看本质,我找到了Netty粘包与半包的这几种解决方案1、粘包与半包啥也不说了,直接上代码是不是有点不太友好,我所谓了,都快过年了,还要啥自行车我上来就是一段代码猛如虎1。1服务器代码publicclassStudyS……湖人从输10分到赢11分!你可能没发现有个人多打了36分钟湖人近期和公牛连续交手了2次,在双方的首次交手中,湖人坐镇主场,此战詹姆斯复出,本以为有了主场加成湖人可以拿下公牛,没想到湖人全场被公牛压制,一度落后21分,虽然湖人在第四节缩……76岁老马斯克与继女生二胎!已有7个孩子,称唯一要做的就是生76岁的老马斯克近日与小41岁的继女剩下二胎孩子,5年前,他俩就育有一子。接受采访时他更是直言:我们在地球上唯一要做的事情就是生育。虽然老马和小马关系紧张已经不是什……分享5款可以录屏的软件,录屏幕视频软件,亲测好用很多小伙伴都会使用电脑来作为自己办公、娱乐、学习生活的工具。在电脑上安装录屏软件,可以轻松的协助我们进行网课录制、会议录制、影剧片段录制等。网络上的录屏软件有很多,今天小编分享……小米13Pro对比vivoX90Pro,同样搭载一英寸大底,vivoX90Pro小米13Pro性能天玑9200LPDDR5X(512GB)LPDDR5UFS4。0骁龙8Gen2LPDDR5XUFS4。……在更多设备上运行GoogleMeet并使其与Zoom兼容谷歌正试图将其Meet视频会议软件扩展到更多设备,并使专为Meet设计的硬件与Zoom更兼容。周三,该公司宣布在ChromeOS上运行良好的企业版Meet将登陆运行Androi……武林风一龙又双叒要复出,34岁的他还抗揍吗?近日,《武林风》官微突然重磅宣布武僧一龙即将重回擂台,此消息一经公布,整个搏击圈儿一片沸腾,作为龙迷来说,一龙永远是中国搏击的代表人物,是擂台永远滴神,因为他对中国搏击的发展居……张庭林瑞阳23年前周一见露馅4次耍弄记者!被骂到离开老家张庭林瑞阳23年前周一见露馅?4次耍弄记者:婚外情被骂到离开老家!张庭和林瑞阳一直以恩爱夫妻的面目示人,实际上两人的情史真是一地鸡毛,曾经因为婚外情被骂到离开老家,夫妻二人到了……不浪费东西,不浪费时间,养成好习惯,就是积累福报在这个世界上,损耗福报最快的东西往往是在大家眼里看到并不贵重的东西,比如我们生活用的水电,我们吃的米饭。我们要节约用水用电,并不是我们用不起这个水电,而是要为国家节约资源,也是……中国移动用户有福了!移动又一项新功能,所有用户可免费使用中国移动也许大家都不陌生,我从2002年开始使用中国移动的,到现在刚好二十年了。期间一直没有换过手机号,也许我对移动是一种情怀吧,移动给我的感觉就是信号好点,网速快一点,从2G……头发有多少根,你知道吗?头发有多少根?又是怎么形成的?头发是由没有生命体质的硬质蛋白,约占头发总量的85到90。另外水、类脂物、色素和微量元素也是头发中不可缺少的成分。每个人头发约在10万根左右……中国具有民居风味的四大古城古城的美,让人陶醉不知归路,去过的人都流连忘返,中国四大古城反应了那个年代居民的生活特点,湘黔古镇清秀灵逸,水乡古村小巧精致,北方大院富贵大气,徽派古村独具大家风范。。。。。。……
上班族必看,120HzOLEDRX3060难得万金油轻薄本,祖国颂天津2035人口0。2亿,2大核心,6条走廊,8大产业,7区跳出题材内卷,极品飞车第22部作品把风格化给玩明白了迪卡侬全系滑板解读,总有一款适合你和你的娃流浪地球2郭帆导演好的科幻片,不止会讲故事免费的高速公路,我的床车旅游爱好者出发了(一)晏平起名,虎宝宝起名,生一儿一女这样取名南京老城南最著名的明清名人大宅,如今人人都可免费游拉不下脸就别扮丑,这些女星太狠了,扮起丑来连自己都不放过汽车出口量超越德国,跃居全球第二!中国汽车被谁买走了?鉴报守住安全底线后碧桂园转向一二线城市重启拿地三年级上册音乐教学工作计划康定跑马山值得去吗每年四月初八这里异常热闹初中生野炊活动作文辽宁潜力新人遭杨鸣怒推!是恨铁不成钢还是杀鸡儆猴?世台联主席不会终身禁赛!中国斯诺克迎来三大喜讯!后起之秀妈妈随意变道的危害和处罚帽子里的秘密欧文3575杜兰特三双篮网134126击败步行者成功的定义跟领导出差受了老罪了!为了节省出差费用,领导是能省就省,不能

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找美丽时装彩妆资讯历史明星乐活安卓数码常识驾车健康苹果问答网络发型电视车载室内电影游戏科学音乐整形