2011-10-18 22 views
14

Khi đọc hướng dẫn Netty, tôi đã tìm thấy một description đơn giản về cách tích hợp Netty và Google Protocol Buffers. Tôi đã bắt đầu điều tra ví dụ của nó (vì không có thêm thông tin trong tài liệu) và viết một ứng dụng đơn giản như ứng dụng thời gian địa phương ví dụ. Nhưng ví dụ này là sử dụng khởi tạo tĩnh trong PipeFactory Class, ví dụ:Netty + ProtoBuffer: Một vài thông báo liên lạc cho một kết nối

import org.jboss.netty.channel.ChannelPipeline; 
import org.jboss.netty.channel.ChannelPipelineFactory; 
import org.jboss.netty.handler.codec.protobuf.ProtobufDecoder; 
import org.jboss.netty.handler.codec.protobuf.ProtobufEncoder; 
import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; 
import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; 

import static org.jboss.netty.channel.Channels.pipeline; 

/** 
* @author sergiizagriichuk 
*/ 
class ProtoCommunicationClientPipeFactory implements ChannelPipelineFactory { 

    public ChannelPipeline getPipeline() throws Exception { 
     ChannelPipeline p = pipeline(); 
     p.addLast("frameDecoder", new ProtobufVarint32FrameDecoder()); 
     p.addLast("protobufDecoder", new ProtobufDecoder(Communication.DataMessage.getDefaultInstance())); 

     p.addLast("frameEncoder", new ProtobufVarint32LengthFieldPrepender()); 
     p.addLast("protobufEncoder", new ProtobufEncoder()); 

     p.addLast("handler", new ProtoCommunicationClientHandler()); 
     return p; 
    } 

} 

(Xin hãy xem tại dòng p.addLast("protobufDecoder", new ProtobufDecoder(Communication.DataMessage.getDefaultInstance()));) và chỉ là một nhà máy có thể được tạo ra (như tôi hiểu) cho ClientBootstrap lớp, ý tôi là bootstrap.setPipelineFactory() phương pháp . Vì vậy, trong tình huống này, tôi có thể sử dụng ONE nhắn gửi đến máy chủ và ONE nhắn nhận được từ máy chủ và nó có hại cho tôi, và tôi nghĩ rằng không chỉ cho tôi :(Làm thế nào tôi có thể sử dụng thông điệp khác nhau đến và đi từ chỉ một kết nối? có lẽ tôi có thể tạo ra một vài protobufDecoder như

p.addLast("protobufDecoder", new ProtobufDecoder(Communication.DataMessage.getDefaultInstance())); 
p.addLast("protobufDecoder", new ProtobufDecoder(Communication.TestMessage.getDefaultInstance())); 
p.addLast("protobufDecoder", new ProtobufDecoder(Communication.SrcMessage.getDefaultInstance())); 

hoặc kỹ thuật khác này? Thanks a lot.

+0

Bạn có thể thêm nhiều bộ giải mã/bộ mã hóa trong đường ống, nhưng chúng sẽ có thể chuyển dữ liệu mà chúng không biết cách xử lý. Nhìn vào [nguồn netty tại github] (https://github.com/netty/netty/blob/master/src/main/java/org/jboss/netty/handler/codec/protobuf/ProtobufDecoder.java) Có vẻ như Thực tế không phải là như vậy. Vì vậy, có lẽ có một cách để làm điều đó, nhưng tôi hoài nghi nó là đơn giản. Hãy thử anyway và chia sẻ kết quả :) – Slartibartfast

+0

@Slartibartfast Vâng, nó không phải là đơn giản và muốn làm việc chăm chỉ: ( –

Trả lời

5

Tôi đã tìm thấy chủ đề của tác giả của netty trong google groups và hiểu rằng tôi phải thay đổi kiến ​​trúc hoặc viết bộ giải mã của riêng mình như tôi đã viết ở trên, Vì vậy, Bắt đầu nghĩ cách nào sẽ dễ dàng và tốt hơn.

+4

Tôi nghĩ rằng điểm của chủ đề nhóm đó là nếu bạn muốn gửi nhiều loại tin nhắn, một giải pháp là xác định 1 mục đích chung "chứa thông báo" (giả sử 'ProtocolMessage') trong protobuf sẽ chứa 1 hoặc nhiều hơn các loại tin nhắn. Sau đó, bạn sẽ sử dụng bộ giải mã protobuf cho loại thông báo 'ProtocolMessage' và để lại bất kỳ giải thích nào khác cho trình xử lý tin nhắn của bạn trong Netty. – tmbrggmn

+0

Vâng, tôi đã hiểu, cảm ơn. –

2

về mặt lý thuyết này có thể được thực hiện bằng cách thay đổi các đường ống dẫn cho mỗi tin nhắn gửi đến cho phù hợp tin nhắn đến. Hãy xem port unification ví dụ trong Netty.

trình tự sẽ là:
1) Trong bộ giải mã khung này hay cách khác "DecoderMappingDecoder" bạn đánh dấu vào loại thông điệp của tin nhắn gửi đến
2) Sửa đổi các đường ống dẫn động như thể hiện trong ví dụ

Nhưng tại sao không sử dụng kết nối khác nhau và làm theo trình tự này:
1) Thêm bộ giải mã khác trong đường ống dựa trên tin nhắn gửi đến chỉ một lần.
2) Thêm cùng trường hợp xử lý ngược dòng kênh làm trình xử lý cuối cùng trong đường ống, theo cách này tất cả các thư được định tuyến đến cùng một cá thể, gần giống như có một kết nối.

+0

Về mặt lý thuyết chúng ta nên sửa đổi bộ giải mã để đọc một số id từ bytestream và chọn thuật toán chính xác để giải mã, tôi thout về giải pháp này nhưng nó không Tại sao tôi muốn mở một kết nối duy nhất, bởi vì tôi muốn thiết lập máy khách và chuẩn bị kết nối tới máy chủ và sử dụng kết nối này (chỉ một) để gửi TẤT CẢ tin nhắn tới máy chủ, các thông điệp như hoạt động, và kiến ​​trúc hiện tại cung cấp cho tôi khả năng tạo ra nhiều khách hàng cho mỗi hoạt động, tôi nghĩ rằng nó không phải là tốt IDEA! –

+0

Nếu bạn có n loại tin nhắn và n cách khác nhau để giải mã, sau đó bạn vẫn có thể sử dụng cùng một kết nối trong đó một "MappingDecoder" duy nhất sẽ kiểm tra loại thông báo và chuyển nó vào bộ giải mã chính xác để giải mã. Hãy xem bộ giải mã nhúng netty (http://grepcode.com/file/repository.jboss .org/maven2/org.jboss.netty/netty/3.1.4.GA/org/jboss/netty/handler/codec/embedder/DecoderEmbedder.java) có thể cung cấp cho bạn cách sử dụng bộ giải mã mà không cần sử dụng đường dẫn. – Abe

1

Vấn đề không phải là khá hạn chế hoặc encoder/decoder giới hạn Netty. Vấn đề là bộ đệm giao thức của Google đang cung cấp chỉ là một cách để tuần tự hóa/deserialize các đối tượng, nhưng không cung cấp một giao thức. Họ có một số loại thực hiện RPC như một phần của phân phối chuẩn, nhưng nếu bạn sẽ cố gắng thực hiện giao thức RPC của họ sau đó bạn sẽ kết thúc với 3 lớp về mình. Những gì tôi đã làm trong một trong những dự án, là để xác định một thông điệp rằng về cơ bản là một liên minh các thông điệp. Thư này chứa một trường là Loại và trường khác là thông điệp thực tế. Bạn sẽ vẫn kết thúc với 2 lớp không giới hạn, nhưng không phải 3. Theo cách này, ví dụ từ Netty sẽ làm việc cho bạn, nhưng như đã đề cập trong bài trước, bạn phải đặt thêm logic vào trình xử lý logic nghiệp vụ.

3

Nếu bạn đang đi để viết các codecs riêng của mình dù sao, bạn có thể muốn xem xét việc thực hiện các giao diện Externalizable cho các đối tượng dữ liệu tùy chỉnh.

  • Có thể lập trình lại là nỗ lực thấp nhưng hiệu suất kém nhất (sắp xếp mọi thứ).
  • Protobuf là một trade-off tốt giữa nỗ lực và hiệu suất (yêu cầu .proto bảo trì)
  • Externalizable là nỗ lực cao, nhưng hiệu suất tốt nhất (codec tùy chỉnh tối thiểu)

Nếu bạn đã biết dự án của bạn sẽ có để quy mô như một con dê núi, bạn có thể phải đi con đường khó khăn. Protobuf không phải là viên đạn bạc.

2

vấn đề là không có cách nào để phân biệt hai thông điệp protobuf khác nhau với nhau ở định dạng nhị phân. Nhưng có một cách để giải quyết nó trong tệp protobuf:

message AnyMessage { 
    message DataMessage { [...] } 
    optional DataMessage dataMessage = 1; 
    message TestMessage { [...] } 
    optional TestMessage testMessage = 2; 
    message SrcMessage { [...] } 
    optional SrcMessage srcMessage = 3; 
} 

trường tùy chọn không được đặt không tạo ra chi phí. Ngoài ra, bạn có thể thêm một Enum, nhưng nó chỉ là một tiền thưởng.

0

Bạn có thể sử dụng đường hầm thông báo để gửi các loại tin nhắn khác nhau dưới dạng tải trọng trong một tin nhắn đơn. Hy vọng rằng sẽ giúp

0

Sau khi nghiên cứu và chịu đau khổ dài ... Tôi nghĩ ra cách sử dụng thành phần của thư thành một thông báo trình bao bọc. Bên trong thông báo đó, tôi sử dụng phím oneof để giới hạn số lượng đối tượng được phép thành chỉ. Hãy kiểm tra ví dụ:

message OneMessage { 
    MessageType messageType = 1; 

    oneof messageBody { 
     Event event = 2; 
     Request request = 3; 
     Response response = 4; 
    } 

    string messageCode = 5; //unique message code 
    int64 timestamp = 6; //server time 
} 
Các vấn đề liên quan