2013-11-05 48 views
0

我試圖在兩臺使用套接字的計算機之間來回發送數據。數據是以序列化數據包對象的形式存在的。使用套接字的隨機序列化例外

當我在本地網絡上的另一臺計算機上測試程序時,出現隨機SerializationExceptions,導致沒有數據通過。

程序一直髮送不同的數據,所以當它再次發送它時,它有時會通過,有時會再次發生相同的SerializationException。如果我捕捉到異常並保持運行,所有數據最終都會通過,但需要多次嘗試。

異常說:「輸入流不是有效的二進制格式的起始內容(以字節爲單位)爲[字節的數據。」

不知道究竟在何處我的問題所在。我發送的數據量較大(最大〜100kb)總是經過。較小的(50-70字節)有問題。這是我的序列化和讀/寫數據的一切。定義爲這樣

插口:

SocketMain = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 

發送&讀取方法。我知道這可能是一種可怕的方式,可能會成爲我的問題。建議?:

public void SendPacket(Packet P) 
    { 
      using (MemoryStream MS = new MemoryStream()) 
      { 
       BinaryFormatter BF = new BinaryFormatter(); 
       BF.Serialize(MS, P); 
       SocketMain.Send(MS.ToArray()); 
      } 
    } 

    public void ReadPacket() 
    { 
     byte[] BufferArray = new byte[131072]; 
     int BytesReceived = SocketMain.Receive(BufferArray); 

     byte[] ActualData = new byte[BytesReceived]; 
     Buffer.BlockCopy(BufferArray, 0, ActualData, 0, BytesReceived); 

     using (MemoryStream MS = new MemoryStream(ActualData)) 
     { 
      BinaryFormatter BF = new BinaryFormatter(); 
      HandlePacket((Packet)BF.Deserialize(MS)); 
     } 
    } 

示例數據包對象。這是我小的一個。我認爲這可能是造成這個問題的那個,但我不知道我能告訴。

[Serializable()] 
public class Packet4BlockVerify : Packet, ISerializable 
{ 
    public byte Index; 
    public string MD5Hash; 

    public Packet4BlockVerify(int Index, string MD5Hash): base(4) 
    { 
     this.Index = (byte)Index; 
     this.MD5Hash = MD5Hash; 
    } 

    protected Packet4BlockVerify(SerializationInfo info, StreamingContext context) 
    { 
     this.ID = info.GetByte("ID"); 
     this.Index = info.GetByte("Index"); 
     this.MD5Hash = info.GetString("MD5Hash"); 
    } 

    public override void GetObjectData(SerializationInfo info, StreamingContext context) 
    { 
     info.AddValue("ID", this.ID); 
     info.AddValue("Index", this.Index); 
     info.AddValue("MD5Hash", this.MD5Hash); 
    } 
} 

有人看到有什麼不對嗎?

+0

哪裏是你的socket.send /接收你的線程行?我處理髮送/通過添加頁眉和頁腳,在接收器部分閱讀網包。這樣,直到找到頭接收本地網絡數據。 – saeed

+0

我只使用本地計算機進行測試。該計劃旨在通過互聯網使用。 數據包的發送和接收主要在同一個線程上結束,在收到數據包時立即通過發送另一個適當的數據包來響應。 – WildBamaBoy

+0

我沒有看到你的發佈代碼的任何特別提示,但是,認爲你的邏輯不夠棘手。有一些標準的網絡編程示例可以幫助你。對於你的問題,需要一個完整的源代碼來重現它的錯誤。 – saeed

回答

2

您沒有讀取您發送的所有字節。您的接收電話:

int BytesReceived = SocketMain.Receive(BufferArray); 

返回任意數量的字節。您將需要預先發送剩餘字節大小的字節,然後在嘗試反序列化之前繼續讀取,直到獲得所有字節。

TCP發送一個連續的字節流,以便您的接收調用讀取任意大小的塊。其中一個重載可以指定想要接收的字節數,以便在讀取您期望的數字字節之後可以使用它。例如

// Warning untested! (but you get the idea) 

// when sending 
var payload = MS.ToArray(); 
var payloadSize = payload.Length; 
mySocket.Send(BitConverter.GetBytes(payloadSize)); 
mySocket.Send(payload); 

// when recieving 
mySocket.Recieve(myBuffer, sizeof(int), SocketFlags.None); 
var payloadSize = BitConverter.ToInt32(myBuffer, 0); 
mySocket.Recieve(myBuffer, payloadSize, SocketFlags.None); 
// now myBuffer from index 0 - payloadSize contains the payload you sent 
+0

看起來好像你是正確的。我使用控制檯記錄發送和接收的數據量,我沒有收到全部內容。雖然我不確定我會如何去做你所說的話。你可以發表一個例子嗎? – WildBamaBoy

+0

用例如 – markmnl

+0

的僞代碼更新了我的答案有道理。在序列化過程中仍然會出現一些奇怪的(不同的)錯誤,但現在它確實發揮了很大的作用。 – WildBamaBoy