2009-02-25 36 views
6

Đây là loại nhánh của other question của tôi. Đọc nó nếu bạn thích, nhưng nó không cần thiết. Về cơ bản, tôi nhận ra rằng để sử dụng hiệu quả C#'s BeginReceive() trên các tin nhắn lớn, tôi cần (a) đọc chiều dài gói đầu tiên, sau đó đọc chính xác nhiều byte hoặc (b) sử dụng phần cuối của -packet delimiter. Câu hỏi của tôi là, hoặc là một trong những hiện diện trong bộ đệm giao thức? Tôi đã không sử dụng chúng được nêu ra, nhưng đi qua các tài liệu hướng dẫn nó không có vẻ như có một tiêu đề chiều dài hoặc một dấu phân cách.Làm thế nào để phát hiện khi nhận được một thông báo Protocol Buffer?

Nếu không, tôi nên làm gì? Tôi có nên chỉ cần xây dựng thông điệp sau đó tiền tố/hậu tố nó với chiều dài tiêu đề/EOP delimiter?

Trả lời

14

Bạn cần bao gồm kích thước hoặc điểm đánh dấu kết thúc trong giao thức của mình. Không có gì được tích hợp vào các socket (TCP/IP) dựa trên luồng khác ngoài việc hỗ trợ một chuỗi octet vô hạn định tùy ý chia thành các gói riêng biệt (và các gói có thể bị tràn quá cảnh).

Cách tiếp cận đơn giản là cho mỗi "thông báo" có tiêu đề kích thước cố định, bao gồm cả phiên bản giao thức và kích thước tải trọng và bất kỳ dữ liệu cố định nào khác. Sau đó, nội dung tin nhắn (tải trọng).

Tùy chọn chân trang thư (kích thước cố định) có thể được thêm bằng tổng kiểm tra hoặc thậm chí chữ ký mã hóa (tùy thuộc vào yêu cầu về độ tin cậy/bảo mật của bạn).

Biết kích thước tải trọng cho phép bạn tiếp tục đọc một số byte sẽ đủ cho phần còn lại của thư (và nếu đọc hoàn thành ít hơn, hãy đọc một lần nữa cho các byte còn lại cho đến khi toàn bộ thư đã được nhận).

Có một chỉ số thông điệp cuối cũng làm việc, nhưng bạn cần phải xác định làm thế nào để xử lý các thông điệp của bạn có chứa chuỗi octet cùng ...

1

TCP/IP, cũng như UDP, gói bao gồm một số tài liệu tham khảo để kích thước của chúng . IP header chứa trường 16 bit chỉ định độ dài của tiêu đề IP dữ liệu theo byte. TCP header chứa trường 4 bit chỉ định kích thước của tiêu đề TCP trong các từ 32 bit. UDP header chứa trường 16 bit chỉ định độ dài của tiêu đề UDP dữ liệu theo byte.

Đây là điều.

Sử dụng ổ cắm tiêu chuẩn chạy trong Windows, cho dù bạn đang sử dụng không gian tên System.Net.Sockets trong C# hoặc công cụ Winsock gốc trong Win32, bạn sẽ không bao giờ thấy tiêu đề IP/TCP/UDP . Các tiêu đề này bị tước đi để những gì bạn nhận được khi bạn đọc ổ cắm là tải trọng thực tế, tức là dữ liệu đã được gửi.

Mẫu điển hình từ mọi thứ tôi từng thấy và thực hiện bằng cách sử dụng ổ cắm là bạn xác định tiêu đề cấp ứng dụng đứng trước dữ liệu bạn muốn gửi. Ở mức tối thiểu, tiêu đề này phải bao gồm kích thước của dữ liệu để theo dõi. Điều này sẽ cho phép bạn đọc toàn bộ "thông điệp" một cách toàn bộ mà không phải đoán kích thước của nó. Bạn có thể nhận được như ưa thích như bạn muốn với nó, ví dụ, mẫu đồng bộ, CRCs, phiên bản, loại tin nhắn, vv, nhưng kích thước của "tin nhắn" là tất cả các bạn thực sự cần.

Và đối với những gì đáng giá, tôi khuyên bạn nên sử dụng tiêu đề thay vì dấu phân cách cuối gói. Tôi không chắc chắn nếu có một bất lợi signficant để phân định EOP, nhưng tiêu đề là cách tiếp cận được sử dụng bởi hầu hết các giao thức IP tôi đã nhìn thấy.Ngoài ra, nó có vẻ trực quan hơn với tôi để xử lý một thông báo ngay từ đầu thay vì đợi một số mẫu xuất hiện trong luồng của tôi để cho biết rằng thông điệp của tôi đã hoàn tất.

EDIT: Tôi chỉ mới biết về dự án Bộ đệm giao thức của Google. Từ những gì tôi có thể nói, nó là một chương trình serialization/de-serialization nhị phân cho WCF (tôi chắc chắn đó là một sự đơn giản hóa quá). Nếu bạn đang sử dụng WCF, bạn không phải lo lắng về kích thước của các tin nhắn được gửi bởi vì hệ thống ống nước WCF chăm sóc điều này đằng sau hậu trường, đó có lẽ là lý do tại sao bạn không tìm thấy bất cứ điều gì liên quan đến chiều dài tin nhắn trong giao thức Tài liệu đệm. Tuy nhiên, trong trường hợp của ổ cắm, biết kích thước sẽ giúp đỡ rất nhiều như đã thảo luận ở trên. Tôi đoán là bạn sẽ tuần tự hóa dữ liệu của bạn bằng cách sử dụng Protocol Buffers và sau đó tack vào bất kỳ tiêu đề ứng dụng bạn đưa ra trước khi gửi nó. Ở phía bên nhận, bạn sẽ kéo tiêu đề ra và sau đó xóa đi phần còn lại của tin nhắn.

+0

Nếu bạn có nghĩa là protobuf-net, không có nó không chỉ dành cho WCF; có các ví dụ về ổ cắm trong dự án. –

3

Tôi đồng ý với Matt rằng đầu trang tốt hơn chân trang cho Bộ đệm giao thức vì lý do chính là PB là giao thức nhị phân, có vấn đề với chân trang không phải là chuỗi thư hợp lệ. Rất nhiều giao thức dựa trên chân trang (thường là các giao thức EOL) hoạt động vì nội dung thư nằm trong phạm vi được xác định (thường là 0x20 - 0x7F ASCII).

Một cách tiếp cận hữu ích là có mã mức thấp nhất của bạn chỉ đọc bộ đệm ra khỏi ổ cắm và hiển thị chúng lên một lớp khung để lắp ráp toàn bộ các thư và ghi nhớ một phần (tôi trình bày cách tiếp cận không đồng bộ với điều này (sử dụng CCR) here, mặc dù cho một giao thức dòng).

Để nhất quán, bạn luôn có thể xác định thư của mình dưới dạng thông báo PB có ba trường: int cố định làm chiều dài, enum là loại và chuỗi byte chứa dữ liệu thực. Điều này giữ cho toàn bộ giao thức mạng của bạn trong suốt.

6

Xin lỗi vì đã đến muộn tại bữa tiệc. Tôi là tác giả của protobuf-net, một trong những triển khai C#. Đối với việc sử dụng mạng, bạn nên xem xét các phương pháp "[De] SerializeWithLengthPrefix" - theo cách đó, nó sẽ tự động xử lý độ dài cho bạn. Có những ví dụ trong nguồn.

Tôi sẽ không đi sâu vào chi tiết về bài đăng cũ, nhưng nếu bạn muốn biết thêm, hãy thêm nhận xét và tôi sẽ liên hệ lại với bạn.

Các vấn đề liên quan