2010-06-30 55 views
5

Tôi có một thông điệp đơn giản:Đọc Tin nhắn Protobuf trong C#

kiểm tra gói;

tin nhắn sendName {

tùy chọn chuỗi tên người dùng = 1;

}

Các tuyệt vời VS Plugin tạo ra cs file:

kiểm tra namespace {

[global :: System.Serializable toàn cầu :: ProtoBuf.ProtoContract (Tên = @ "sendName")]

lớp công khai một phần sendName: toàn cầu :: ProtoBuf.IExtensible {

public sendName() {}  

private string _username = ""; 
[global::ProtoBuf.ProtoMember(1, IsRequired = false, [email protected]"username", DataFormat = > global::ProtoBuf.DataFormat.Default)] 
[global::System.ComponentModel.DefaultValue("")] 
public string username 
{ 
    get { return _username; } 
    set { _username = value; } 
} 
private global::ProtoBuf.IExtension extensionObject; 
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing) 

    { return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing); } } } 

Tôi gửi một thông điệp từ phía java bằng cách sử dụng

objName.build() writeTo ((FileOutputStream) socket.getOutputStream()).

Trong ứng dụng # C của tôi, trong đó hoạt động như Listener Socket, tôi có một phương pháp gọi là Nghe mà nghe cho thông điệp gửi của khách hàng java:

public void Listen()

{

 IPAddress ipAddress = IPAddress.Parse("127.0.0.1"); 

     TcpListener listener = new TcpListener(ipAddress, 4055); 

     TcpClient client = null; 

     listener.Start(); 

     while (true) 

     { 

      Debug.WriteLine("Waiting for a Connection"); 

      client = listener.AcceptTcpClient(); 

      Stream stream = client.GetStream(); 

      // sendName sendNameObj = Serializer.Deserialize<sendName>(stream); 

     } 

}

Tôi rõ ràng là thiếu một số vấn đề cơ bản ở đây.

Tôi nên sử dụng phương pháp nào để nhận đối tượng sendName?


Khi tôi gỡ lỗi mã của mình trong C#, trình gỡ lỗi sẽ thoát khi tôi gọi phương thức DeserializeWithLengthPrefix.

Đây là mã # C của tôi:

private void Listen() 
    { 
     IPAddress ipAddress = IPAddress.Parse("127.0.0.1"); 
     TcpListener listener = new TcpListener(ipAddress,4055); 
     listener.Start(); 
     listener.BeginAcceptSocket(ClientConnected, listener); 
    } 

    private void ClientConnected(IAsyncResult result) 
    { 
     TcpListener server = (TcpListener)result.AsyncState; 
     using (TcpClient client = server.EndAcceptTcpClient(result)) 
     using (NetworkStream stream = client.GetStream()) 
     { 
      try 
      { 
       //SendNameMessage sendNameObj = Serializer.Deserialize<SendNameMessage>(stream); 
       SendNameMessage sendNameObj = Serializer.DeserializeWithLengthPrefix<SendNameMessage>(stream, PrefixStyle.Fixed32); 
       string name = sendNameObj.sendName; 
       if (name != null && name.Length > 0) 
       { 
        nameTextBox.Text = name; 
       } 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show(ex.Message); 
      } 
     } 
    } 

Đây là mã java của tôi:

 SendNameMessage.Builder sendNameMessageObj = null; 
     sendNameMessageObj = SendNameMessage.newBuilder(); 
     sendNameMessageObj.setSendName("Protobuf-net"); 

     SocketRequest.INSTANCE.openSocket(); 
     sendNameMessageObj.build().writTo(SocketRequest.INSTANCE.getWriter()); 

Trả lời

5

Các Serializer.Deserialize<sendName>(stream); nên làm điều đó, nhưng tôi đoán rằng nó được treo vĩnh viễn? Lý do ở đây là các thông điệp protobuf không có bộ kết thúc sẵn có, do đó, mặc định là nó đọc cho đến cuối luồng - điều này sẽ không xảy ra cho đến khi bạn đóng socket.

Để giải quyết vấn đề này, một mẹo phổ biến là tiền tố tin nhắn có độ dài và giới hạn bản thân với điều đó. Có thể có một cách sẵn có để xử lý điều đó trong việc thực hiện Java, hoặc bạn có thể xử lý nó theo cách thủ công. Về phía C#, protobuf-net có DeserializeWithLengthPrefix, chấp nhận một enum để xác định cách bạn đã mã hóa nó. Để đơn giản, tôi sẽ đề nghị một mã hóa 32-bit cơ bản của độ dài nhỏ (mà ánh xạ tới PrefixStyle.Fixed32).


Chỉnh sửa/nhận xét: hai phải khớp. Tại thời điểm bạn đang tuần tự hóa mà không cần tiền tố độ dài, nhưng deserializing mong đợi tiền tố độ dài. API Java có hiển thị cơ chế để có được độ dài dữ liệu trước bạn viết nó không? Nếu không, có thể viết đầu tiên vào một bộ đệm tạm thời, xem bạn đã viết bao nhiêu, sau đó viết độ dài và cuối cùng là dữ liệu.

Hoặc; nếu bạn chỉ gửi một tin nhắn duy nhất - chỉ cần đóng luồng và sử dụng Deserialize (không có tiền tố độ dài). Tôi có sẵn một ví dụ về ổ cắm đa thông điệp C# -to-C# nhưng tôi không thể nhận xét nhiều về phía java ...

+0

Marc, tôi tiếp tục nhận được ngoại lệ "Mã thông báo không hợp lệ: 0". Bạn có thể cho tôi biết điều này có ý nghĩa gì không? – sonu

+0

@sonu - điều đó có nghĩa là nó đang tìm kiếm 0 lúc bắt đầu một loạt dữ liệu, đó là * không bao giờ * hợp lệ. Bạn có thể thêm bất kỳ chi tiết nào xung quanh dòng dữ liệu trông như thế nào và mã trông như thế nào khi bạn nhìn thấy điều này? –

+0

Xin lỗi tôi mới tham gia stackoverflow. Tôi đã thêm mã bằng cách chỉnh sửa bài đăng. Khi tôi đóng socket ở phía bên java, tôi nhận được một ngoại lệ: "Đã cố gắng đọc qua cuối luồng" – sonu

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