2015-07-10 24 views
0

我正在開發一個項目,該項目利用簡單的Socket連接在Packet.cs對象之間傳遞客戶端和服務器之間的小型變量作爲「旅行模式」。客戶端和服務器是不同項目的一部分,但是同樣的解決方案,Packet.cs也是一個單獨的「共享項目」。解碼消息時的反序列化異常

這是我packet.cs文件:

using System; 
using System.Net; 
using System.IO; 
using System.Runtime.Serialization.Formatters.Binary; 
using System.Threading.Tasks; 
using System.Collections.Generic; 

namespace ConnectionData 
{ 
    [Serializable] 
    public class Packet 
    { 
     // these are all the different types of things we can send 
     public List<string> gData; 
     public string packetString; 
     public int packetInt; 
     public bool packetBool; 
     public PacketType packetType; 

     // senderID is going to be the unique GUID that we generated 
     public string senderID; 


     public Packet (PacketType type, string senderID) 
     { 
      gData = new List<String>(); 
      this.senderID = senderID; 
      this.packetType = type; 
     } 

     public Packet(byte[] packetBytes) 
     { 
      // deconstructs the bytes we received into packet form 
      BinaryFormatter bf = new BinaryFormatter(); 
      MemoryStream ms = new MemoryStream (packetBytes); 

      Packet p = (Packet)bf.Deserialize (ms); 
      ms.Close(); 

      // assigns all the values from the packet info we received in byte form 
      this.gData = p.gData; 
      this.packetInt = p.packetInt; 
      this.packetBool = p.packetBool; 
      this.senderID = p.senderID; 
      this.packetType = p.packetType; 
     } 

     // this converts the whole packet object into a byte array to send through the socket 
     public byte[] ToBytes() 
     { 
      BinaryFormatter bf = new BinaryFormatter(); 
      MemoryStream ms = new MemoryStream(); 

      bf.Serialize (ms, this); 
      byte[] bytes = ms.ToArray(); 
      ms.Close(); 
      return bytes; 
     } 

     // this function will return the active IP address of the system. if it 
     // cant find one, it returns default local address 
     public static string GetIP4Address() 
     { 
      // this lists all addresses shown in IPConfig 
      IPAddress[] ips = Dns.GetHostAddresses (Dns.GetHostName()); 

      foreach(IPAddress i in ips) 
      { 
       // if there's an IP4 address in the list, return it 
       if (i.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) 
       { 
        return i.ToString(); 
       }  
      } 

      // else return local address 
      return "127.0.0.1"; 
     } 

     // enum makes it so we can define different strings, makes the packetType really easy to work with 
     // allows us to define what kind of packet it is 
     public enum PacketType 
     { 
      Registration, CloseConnection, Command 
     } 
    } 
} 

這是我用什麼來發送數據。當我在服務器上創建的消息發送到客戶端,我只需撥打Packet p = new Packet(Packet.PacketType.Command);socket.Send(p.ToBytes());

接收的數據包(兩個項目)用途:

public void Data_IN (object cSocket) 
     { 
      Socket clientSocket = (Socket)cSocket; 

      byte[] buffer; 
      int readBytes; 

      while (Server.listening) { 
       // sets our buffer array to the max size we're able to receive 
       buffer = new byte[clientSocket.SendBufferSize]; 

       // gets the amount of bytes we've received 
       readBytes = clientSocket.Receive (buffer); 

       // if we actually recieve something, then sort through it 
       if (readBytes > 0) { 
        // handle data 
        Packet packet = new Packet (buffer); 
        DataManager (packet); // handles the packet data 
       } 
      } 
     } 

產生的問題是,當我嘗試發送在第一個連接上註冊數據包。我啓動我的服務器項目,讓它執行等待,一切正常。客戶端是能夠連接和服務器發送其在這裏創建了註冊分組:

Packet p = new Packet (Packet.PacketType.Registration, Server.guid); 
p.packetString = HeartCore.commandKey; // commandKey is a static string variable 
clientSocket.Send (p.ToBytes()); 

服務器表明它已經成功發送,然後客戶端會拋出異常。好極了!客戶端處理收到的數據包,如上圖所示Data_IN。它創建於

if (readBytes > 0) { 
    // handle data 
    Packet packet = new Packet (buffer); // this is where it stops 
    DataManager (packet); // handles the packet data 
} 

public Packet(byte[] packetBytes) 
{ 
    // deconstructs the bytes we received into packet form 
    BinaryFormatter bf = new BinaryFormatter(); 
    MemoryStream ms = new MemoryStream (packetBytes); 

    Packet p = (Packet)bf.Deserialize (ms); //EXCEPTION OCCURS HERE 
    ms.Close(); 
    ... 

新的數據包後,如果你還記得,包類有一個構造函數中的字節[]緩衝區,並將其轉換成一個對象,則會出現異常的權利,然後將臨時數據包對象中的值複製到正在使用的實際對象。

所引發的異常是

System.Runtime.Serialization.SerializationException: Couldn't find assembly 'Heart' ---> System.Exception: Could not load file or assembly 'Heart' or one of its dependencies. The system cannot find the file specified. 
    at System.AppDomain.Load (System.String assemblyString, System.Security.Policy.Evidence assemblySecurity, Boolean refonly) [0x00000] in <filename unknown>:0 
    at System.AppDomain.Load (System.String assemblyString) [0x00000] in <filename unknown>:0 
    at at (wrapper remoting-invoke-with-check) System.AppDomain:Load (string) 
    at System.Reflection.Assembly.Load (System.String assemblyString) [0x00000] in <filename unknown>:0 
    at System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetDeserializationType (Int64 assemblyId, System.String className, Boolean throwOnError) [0x00000] in <filename unknown>:0 
    --- End of inner exception stack trace --- 
    at System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetDeserializationType (Int64 assemblyId, System.String className, Boolean throwOnError) [0x00000] in <filename unknown>:0 
    at System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetDeserializationType (Int64 assemblyId, System.String className) [0x00000] in <filename unknown>:0 
    at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadTypeMetadata (System.IO.BinaryReader reader, Boolean isRuntimeObject, Boolean hasTypeInfo) [0x00000] in <filename unknown>:0 
    at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObjectInstance (System.IO.BinaryReader reader, Boolean isRuntimeObject, Boolean hasTypeInfo, System.Int64& objectId, System.Object& value, System.Runtime.Serialization.SerializationInfo& info) [0x00000] in <filename unknown>:0 
    at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObject (BinaryElement element, System.IO.BinaryReader reader, System.Int64& objectId, System.Object& value, System.Runtime.Serialization.SerializationInfo& info) [0x00000] in <filename unknown>:0 
    at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObject (BinaryElement element, System.IO.BinaryReader reader, System.Int64& objectId, System.Object& value, System.Runtime.Serialization.SerializationInfo& info) [0x00000] in <filename unknown>:0 
    at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadNextObject (BinaryElement element, System.IO.BinaryReader reader) [0x00000] in <filename unknown>:0 
    at System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadObjectGraph (BinaryElement elem, System.IO.BinaryReader reader, Boolean readHeaders, System.Object& result, System.Runtime.Remoting.Messaging.Header[]& headers) [0x00000] in <filename unknown>:0 
    at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.NoCheckDeserialize (System.IO.Stream serializationStream, System.Runtime.Remoting.Messaging.HeaderHandler handler) [0x00000] in <filename unknown>:0 
    at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize (System.IO.Stream serializationStream) [0x00000] in <filename unknown>:0 
    at ConnectionData.Packet..ctor (System.Byte[] packetBytes) [0x00016] in /home/austin/Programming/C#/Crystal-Home-Systems/ConnectionData/Packet.cs:63 
    at Shard.Client.Data_IN() [0x0002f] in /home/austin/Programming/C#/Crystal-Home-Systems/Shard/Client.cs:90 
    at System.Threading.Thread.StartInternal() [0x00000] in <filename unknown>:0 

現在,我是半新的C#語言本身,但我有與Java經驗像樣的數目,也做了這種類型的服務器 - 客戶端的工作與之前。我花了大約5個小時左右的時間改變事情,使用谷歌,甚至要求幾個編程的朋友,我們一直無法弄清楚發生了什麼。 Couldn't find assembly 'Heart'引用我對項目Heart的看法,它是發送導致崩潰的數據包的服務器類。

有沒有人有任何想法可能會導致崩潰?我越來越惱火,覺得我失去了超級明顯的東西。我試圖儘可能具體,請讓我知道,如果我忘記了任何問題或如果你需要更多的細節!

非常感謝您的幫助!

編輯:只是爲了澄清,服務器和客戶端都能夠連接沒有問題,嘗試解碼由服務器發送到客戶端的註冊數據包時發生錯誤。另外,它可以在使用mono的Linux系統Kubuntu上運行。我不認爲會有所作爲,但它可能

回答

0

我找到了我的問題的答案。 Packet.cs文件位於共享項目的內部。據我所知,共享項目使用瞭解決方案內所有其他項目的資源,這不是我想要做的。

我嘗試了各種各樣的東西,包括CodeCaster給出的驚人答案,但沒有任何工作。

要解決異常,我將Packet.cs文件重新映射到共享庫項目,而不是共享項目。這允許將Packet.cs文件作爲.dll文件放入構建路徑中,從而使其不具有其他項目的資源。

完美解決方案!我希望這將有助於未來的人!

+0

*'我試過各種各樣的東西,包括CodeCaster給出的驚人答案,但是沒有任何工作。「*,你沒有嘗試他的答案,因爲他的答案的第一句話是告訴你做什麼,你完成了」沒有任何工作後產生「 –

+0

我不是真的確定你在哪裏獲得,解決方案是我爲Packet.cs創建SharedProject的方式。我無法使用SharedProject,我需要一個SharedLibrary。如果這就是他的回答所說的話,我會接受它,但是據我所知它不是。 – PulsePanda

1

通過使用bf.Serialize (ms, this)發送一個數據包,您的客戶端需要包含typeof(this),作爲Heart組件裝配。客戶端然後需要該程序集來反序列化它。

不要序列化內部結構(Packet),序列化您移入程序集並與客戶端共享該類的Payload類。

的問題是,雖然這個代碼:

// gets the amount of bytes we've received 
readBytes = clientSocket.Receive (buffer); 

// if we actually recieve something, then sort through it 
if (readBytes > 0) { 
    // handle data 
    Packet packet = new Packet (buffer); 
    DataManager (packet); // handles the packet data 
} 

可能會在本地主機上運行的小號碼的呼叫,但是當任何嚴重的交通實現它會失敗,因爲buffer就可以包含一半的消息,或三個半消息。

您需要實施組幀協議來檢測單獨的消息。

但是,當你這樣做時,你似乎從頭開始重新創建Protocol Buffers。使用existing libraries這樣的東西。

+0

當你說有效載荷類時,你的意思是[this](https://msdn.microsoft.com/en-us/library/microsoft.sqlserver.management.smo.payload.aspx)?或者我創建的另一個類是可序列化的持有Packet對象的類,以便發送數據包,我會使用'clientSocket.Send(payloadObject.packetObject.ToBytes());' – PulsePanda