- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
在上一篇随笔中,我们探讨了如何实现一套自定义通信协议,其中涉及到的粘包和拆包处理最初是完全自定义实现的,后来则改为了继承 ByteToMessageDecoder 来简化处理.
本篇将重点讨论这两种实现方式在缓存管理上的主要区别,并深入分析其中的不同之处以及值得借鉴的经验和技巧.
无缓存的情况 。
有缓存的情况 。
công cộng lớp học EchoServerHandler mở rộng ChannelInboundHandlerAdapter { riêng tư tĩnh cuối cùng số nguyên HEADER_LENGTH = 4; //消息头部长度 riêng tư ByteBuf buffer = Unpooled.buffer(1024); //缓存残缺消息 @Ghi đè công cộng vô hiệu channelRead(ChannelHandlerContext ctx, Object msg) ném Exception { ByteBuf income = (ByteBuf) msg; //上一次有缓存存在,则本数据包不是消息头开头, nếu như(buffer.readableBytes() > 0) { //进行必要的扩容,下面的readBytes不会自动扩容 buffer.ensureWritable(income.readableBytes()); income.readBytes(buffer, income.readableBytes()); readMsgFromBuffer(buffer); //剩下一点残缺消息 nếu như(buffer.readableBytes() > 0) { //保留剩下的数据,重置读索引为0 System.out.println("缓存剩余字节:"+buffer.readableBytes()); buffer.discardReadBytes(); } khác { //刚刚好,则清空数据 buffer.clear(); } } khác { readMsgFromBuffer(income); //剩下的数据全部写入缓存 nếu như (income.readableBytes() >0) { System.out.println("剩余字节:"+income.readableBytes()); income.readBytes(buffer, income.readableBytes()); } } } //从字节数组中读取完整的消息 riêng tư vô hiệu readMsgFromBuffer(ByteBuf byteBuf) { //剩余可读消息是否包含一个消息头 trong khi(byteBuf.readableBytes() >= HEADER_LENGTH) { byteBuf.markReaderIndex(); //由于可能读不到完整的消息,所以读之前先标记索引位置,方便重置 //读取消息头 byte[] headerBytes = mới byte[4]; byteBuf.readBytes(headerBytes); //获取类型 số nguyên type = headerBytes[0] & 0xFF; //获取消息体长度 số nguyên bodyLength = ((headerBytes[1] & 0xFF) << 16) | ((headerBytes[2] & 0xFF) << 8) | (headerBytes[3] & 0xFF); //不包含请求体 nếu như (byteBuf.readableBytes() < bodyLength) { byteBuf.resetReaderIndex(); //重置读索引到当前消息头位置 phá vỡ; } // 完整消息体已经接收,处理消息 byte[] body = mới byte[bodyLength]; byteBuf.readBytes(body); //System.out.println("type:"+type+"||length:"+bodyLength+"||body:"+new String(body, CharsetUtil.UTF_8)); nếu như(type == 1) { thử { HelloRequest request = HelloRequest.parseFrom(body); System.out.println("收到消息:"+request.toString()); } nắm lấy (Exception e) { System.out.println("解析失败:"+mới String(body, CharsetUtil.UTF_8)); } } khác { System.out.println("消息类型未知:"+type); } } } .... }
使用ByteToMessageDecoder后,数据的解码变得更加简化。只需检查缓冲区是否有足够的数据来提取一个/多个完整的消息.
如果数据不足,解码过程就会结束,无需额外管理缓存.
công cộng lớp học MessageDecoder mở rộng ByteToMessageDecoder { riêng tư tĩnh cuối cùng số nguyên HEADER_LENGTH = 4; //消息头部长度 @Ghi đè được bảo vệ vô hiệu decode(ChannelHandlerContext ctx, ByteBuf in, List
//缓存 riêng tư ByteBuf cumulation; //累加器(用于拼接缓存和新到数据) riêng tư Cumulator cumulator = MERGE_CUMULATOR; //X次channelRead之后,释放已读数据 riêng tư số nguyên discardAfterReads = 16; //累计channelRead次数(每次释放完会重置) riêng tư số nguyên numReads;
1.新到数据存放到缓冲区(使用累加器Cumulator进行数据合并) 。
2.循环调用子类的decode方法,读取消息存入List,直到数据不足 。
3.遍历List,依次传递给下一个处理器 。
提供2种累加器实现,MERGE_CUMULATOR和COMPOSITE_CUMULATOR 。
1)MERGE_CUMULATOR(默认实现) 。
缓存存在的时候,直接进行数据拷贝,与缓存数据进行整合.
下面的代码可以看到,如果缓冲区空间不够,则会进行扩容操作.
跟自定义实现中的"buffer.ensureWritable(income.readableBytes())"一致.
整体思路跟自定义实现差不多,不过它多考虑了两种情况 。
công cộng tĩnh cuối cùng Cumulator MERGE_CUMULATOR = mới Cumulator() { //cumulation是上一次的缓存,in是新到的数据 @Ghi đè công cộng ByteBuf cumulate(ByteBufAllocator alloc, ByteBuf cumulation, ByteBuf in) { thử { cuối cùng ByteBuf buffer; nếu như (cumulation.writerIndex() > cumulation.maxCapacity() - in.readableBytes() || cumulation.refCnt() > 1 || cumulation.isReadOnly()) { // Expand cumulation (by replace it) when either there is not more room in the buffer // or if the refCnt is greater then 1 which may happen when the user use slice().retain() or // duplicate().retain() or if its read-only. // // See: // - https://github.com/netty/netty/issues/2327 // - https://github.com/netty/netty/issues/1764 buffer = expandCumulation(alloc, cumulation, in.readableBytes()); } khác { buffer = cumulation; } //新到数据写入缓存 buffer.writeBytes(in); trở lại buffer; } Cuối cùng { // We must release in in all cases as otherwise it may produce a leak if writeBytes(...) throw // for whatever release (for example because of OutOfMemoryError) in.release(); } } };
2)COMPOSITE_CUMULATOR 。
上面的处理,新到数据与缓存的合并是通过数据拷贝。而下面这种方式,则是使用组合(数据没有移动,只是提供一个整合后的视图) 。
công cộng tĩnh cuối cùng Cumulator COMPOSITE_CUMULATOR = mới Cumulator() { @Override công cộng ByteBuf cumulate(ByteBufAllocator alloc, ByteBuf cumulation, ByteBuf in) { ByteBuf buffer; thử { nếu như (cumulation.refCnt() > 1) { // Expand cumulation (by replace it) when the refCnt is greater then 1 which may happen when the // user use slice().retain() or duplicate().retain(). // // See: // - https://github.com/netty/netty/issues/2327 // - https://github.com/netty/netty/issues/1764 buffer = expandCumulation(alloc, cumulation, in.readableBytes()); buffer.writeBytes(in); } khác { CompositeByteBuf composite; nếu như (cumulation trường hợp của CompositeByteBuf) { //上一次缓存已经是组合对象 composite = (CompositeByteBuf) cumulation; } khác { composite = alloc.compositeBuffer(Integer.MAX_VALUE); //缓存加入组合 composite.addComponent(ĐÚNG VẬY, cumulation); } //新到数据加入组合 composite.addComponent(ĐÚNG VẬY, in); in = vô giá trị; buffer = composite; } trở lại buffer; } Cuối cùng { //由于使用组合方式,数据还在原来的地方。不能直接释放 nếu như (in != vô giá trị) { // We must release if the ownership was not transferred as otherwise it may produce a leak if // writeBytes(...) throw for whatever release (for example because of OutOfMemoryError). in.release(); } } } };
在上述的自定义实现中,每次从缓冲区读取完数据,会释放掉已读数据,防止缓存数据无限增长.
buffer.discardReadBytes(),
而这里做了优化,累积16次读取后,才会进行释放。(channelReadComplete的时候也会触发) 。
这样做的好处,就是可以减少数据拷贝的次数。(discard操作会把已读数据清空,重置读索引,然后把剩余数据往前挪) 。
@Ghi đè công cộng vô hiệu channelRead(ChannelHandlerContext ctx, Object msg) ném Ngoại lệ { //仅处理ByteBuf,其他消息直接传给下一个Handler nếu như (msg trường hợp của ByteBuf) { CodecOutputList out = CodecOutputList.newInstance(); thử { ByteBuf data = (ByteBuf) msg; first = cumulation == vô giá trị; //缓冲区为空,直接赋值 nếu như (first) { cumulation = data; } khác { //使用累加器进行数据合并 cumulation = cumulator.cumulate(ctx.alloc(), cumulation, data); } //调用子类实现,从缓冲区中解析消息 callDecode(ctx, cumulation, out); } nắm lấy (DecoderException e) { ném e; } nắm lấy (Ngoại lệ e) { ném mới DecoderException(e); } Cuối cùng { nếu như (cumulation != vô giá trị && !cumulation.isReadable()) { //缓冲区数据刚好读完,清空缓冲区,清空已读次数 numReads = 0; cumulation.release(); cumulation = vô giá trị; } khác nếu như (++ numReads >= discardAfterReads) { // We did enough reads already try to discard some bytes so we not risk to see a OOME. // See https://github.com/netty/netty/issues/4275 //已读数达到限定次数(默认16),释放已读数据 numReads = 0; discardSomeReadBytes(); } số nguyên kích thước = out.size(); //是不是没解析到消息 decodeWasNull = !out.insertSinceRecycled(); //将解析出来的消息逐个传个下一个Handler fireChannelRead(ctx, out, size); //清空List,下次再用 out.recycle(); } } khác { //直接丢给下一个Handler ctx.fireChannelRead(msg); } }
这里主要通过检查List结果集和数据读取情况,来判断要不要结束解码循环.
được bảo vệ vô hiệu callDecode(ChannelHandlerContext ctx, ByteBuf in, List
核心内容并无太大差异,但 Netty 提供的抽象类在实现上考虑了更多细节,并经过社区的不断演进,功能变得更加稳定和完善.
因此,推荐继承 ByteToMessageDecoder 来实现解码.
最后此篇关于【源码】ByteToMessageDecoder对比自定义实现的文章就讲到这里了,如果你想了解更多关于【源码】ByteToMessageDecoder对比自定义实现的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
Bối cảnh: Gần đây tôi sử dụng JPA rất nhiều và tôi rất ấn tượng về khả năng dễ dàng tạo lớp lưu trữ bền vững cho dự án cơ sở dữ liệu quan hệ khá lớn của mình. Công ty chúng tôi sử dụng nhiều cơ sở dữ liệu không phải SQL, đặc biệt là các cơ sở dữ liệu theo cột. Tôi có một số câu hỏi về khả năng sử dụng JPA với các cơ sở dữ liệu này.
Tôi đã thêm các cấu hình xây dựng này vào maven pom của mình vì tôi muốn các phụ thuộc của Apache Solr được đóng gói cùng với Jar. Nếu không, tôi sẽ nhận được SolarServerException: ClassNotF
giao diện ITurtle { void Fight(); void EatPizza(); } giao diện ILeonardo : ITurtle {
Tôi hy vọng rằng một trong những công cụ ánh xạ đối tượng/quan hệ (ORM) có sẵn cho Java sẽ đáp ứng được các yêu cầu sau: Truy xuất một số lượng lớn hàng bằng cách sử dụng truy vấn JPA hoặc SQL gốc và trả về chúng dưới dạng đối tượng thực thể. Cho phép lặp lại trên các hàng (thực thể) và
Có vẻ là không, vì tôi có mã thực hiện From for và tôi có thể chuyển đổi A thành B bằng .into() nhưng điều tương tự không hiệu quả với Vec .into() a Vec . Hoặc là tôi đã làm hỏng thứ gì đó ngăn cản việc thực hiện Derivation, hoặc điều này không nên xảy ra.
Trong C#, nếu A triển khai IX và B kế thừa từ A, thì liệu B có nhất thiết phải triển khai IX không? Nếu vậy, có phải là do LSP không? Có sự khác biệt nào giữa: 1. Giao diện IX; Lớp A: IX;
Hiện tại, câu hỏi này không phù hợp với định dạng Hỏi & Đáp của chúng tôi. Chúng tôi mong đợi câu trả lời được hỗ trợ bởi các sự kiện, tài liệu tham khảo hoặc chuyên môn, nhưng câu hỏi này có thể gây ra tranh luận, tranh cãi, thăm dò ý kiến hoặc thảo luận mở rộng. Nếu bạn cảm thấy vấn đề này có thể được cải thiện và có thể mở lại, hãy truy cập
Tôi đang đọc mã triển khai (^) của thư viện haskell chuẩn: (^) :: (Num a, Integral b) => a -> b -> a x0 ^ y0 | y0 a -> b ->a expo x0
Tôi sẽ biểu diễn ván cờ vua dưới dạng cấu trúc C++. Tôi nghĩ, lựa chọn tốt nhất sẽ là cấu trúc cây (vì ở mỗi độ sâu, chúng ta có nhiều khả năng di chuyển). Đây có phải là cách tiếp cận tốt không? cấu trúc TreeElement{ SomeMoveType
Tôi đang triển khai thuật toán khớp chuỗi cho cơ sở dữ liệu tên người dùng. Phương pháp của tôi sử dụng cơ sở dữ liệu tên người dùng hiện có và tên người dùng mới mà người dùng muốn, sau đó kiểm tra xem tên người dùng đó đã có người dùng hay chưa. Nếu sử dụng, phương pháp này sẽ trả về tên người dùng với một số chưa được sử dụng trong cơ sở dữ liệu. Ví dụ: "Jia
Tôi đang cố gắng triển khai thuật toán tìm kiếm theo chiều rộng để tìm khoảng cách ngắn nhất giữa hai đỉnh. Tôi đã phát triển một đối tượng Queue để lưu và truy xuất các đối tượng và tôi có một mảng 2D để lưu hai đỉnh đã cho
Hiện tại tôi đang phát triển trò chơi Python của mình bằng ika, sử dụng python 2.5 và tôi quyết định sử dụng công nghệ tìm đường A* cho AI. Tuy nhiên, tôi thấy nó quá chậm so với nhu cầu của mình (3-4 kẻ địch có thể sẽ chậm hơn so với trò chơi, nhưng tôi muốn cung cấp 4-
Tôi đang tìm kiếm một triển khai mã nguồn mở của Kademlia, một bảng băm phân tán trong C/C++. Nó phải nhẹ và chạy được trên nhiều nền tảng (win/linux/mac). Nó phải có khả năng xuất bản thông tin tới DHT và thu thập thông tin đó. Câu trả lời tốt nhất cho OpenDHT là
Tôi đọc được dòng này trong một cuốn sách: "Khi chúng ta yêu cầu triển khai C++ chạy một chương trình, nó sẽ thực hiện bằng cách gọi hàm này." Và tôi muốn biết "Triển khai C++" có nghĩa là gì hoặc chính xác thì nó là gì. giúp đỡ!? Câu trả lời tốt nhất là "Triển khai C++" nghĩa là trình biên dịch cộng với trình liên kết
Tôi đang cố gắng triển khai bài toán ba lô này trong C++ bằng cách sử dụng nhánh và ràng buộc. Có một phiên bản Java trên trang web này: Triển khai nhánh và ràng buộc cho knapsack Tôi đã cố gắng để có được phiên bản C++ của mình để in
Có nhiều trường hợp tôi cần truy cập thuật toán băm phù hợp trong C#, từ ghi đè GetHashCode đến thực hiện so sánh/tra cứu dữ liệu nhanh. Tôi thấy băm FNV là một thuật toán băm rất đơn giản/tốt/nhanh. Tuy nhiên, tôi chưa bao giờ thấy một triển khai C#
Chiến lược thay thế bộ nhớ đệm LRU thư mục ý tưởng cốt lõi không áp dụng thuật toán kịch bản thuật toán triển khai cơ bản tối ưu hóa
1. Giới thiệu Trong bài viết trước, chúng tôi đã đề cập đến việc các hệ tọa độ hình chữ nhật không gian được chuyển đổi cho nhau. Khi thực hiện chuyển đổi tọa độ trắc địa và lập bản đồ, tình huống thường gặp là: chuyển đổi góc nhỏ của hai hệ tọa độ hình chữ nhật. Đây là những gì chúng ta thường sử dụng trong quá trình xử lý dữ liệu khảo sát và lập bản đồ, hệ tọa độ WGS-84, hệ tọa độ Bắc Kinh 54
Trong quá trình phát triển phần mềm, đôi khi chúng ta cần kiểm tra dữ liệu trong cơ sở dữ liệu theo định kỳ và kích hoạt hành động khi tìm thấy dữ liệu mới. Để đạt được yêu cầu này, chúng tôi sẽ tiến hành một cuộc trình diễn đơn giản trong .Net 7. PeriodicTimer.
Tìm kiếm nhị phân Thuật toán tìm kiếm nhị phân, nói một cách đơn giản, là đưa ra một khóa giá trị trong một mảng có thứ tự, sau đó so sánh nó với phần tử giữa của mảng. Nếu khóa lớn hơn giá trị giữa, hãy thực hiện phép so sánh tiếp theo sau phần tử giữa cho đến khi tìm được giá trị bằng, sau đó bạn có thể biết được vị trí của nó.
Tôi là một lập trình viên xuất sắc, rất giỏi!