2013-02-06 44 views
2

早上,我有一个TCP服务器和一个TCP客户端。 这里是服务器的代码:通过网络发送自定义结构 - SerializationException

public static class Server 
{ 
    private static IPEndPoint endPoint; 

    private static TcpListener tcpServer; 
    private static List<Client> clients; 
    private static Thread threadListen; 

    private static ASCIIEncoding encoding; 

    public static void Initialize(IPAddress allowedIPAddress, int port) 
    { 
     endPoint = new IPEndPoint(allowedIPAddress, port); 

     tcpServer = new TcpListener(endPoint); 
     clients = new List<Client>(); 
     threadListen = new Thread(new ThreadStart(Listen)); 

     encoding = new ASCIIEncoding(); 
    } 

    public static void Start() 
    { 
     threadListen.Start(); 
    } 

    public static byte[] PacketToArray(Packet packet) 
    { 
     IFormatter formatter = new BinaryFormatter(); 
     MemoryStream stream = new MemoryStream(); 

     formatter.Serialize(stream, packet); 
     byte[] packetArray = stream.GetBuffer(); 

     stream.Close(); 

     return packetArray; 
    } 

    public static Packet ArrayToPacket(byte[] array) 
    { 
     IFormatter formatter = new BinaryFormatter(); 
     MemoryStream stream = new MemoryStream(array); 

     Packet packet = new Packet(); 
     packet = (Packet) formatter.Deserialize(stream); 

     stream.Close(); 

     return packet; 
    } 

    public static void Send(Client target, Packet packet) 
    { 
     byte[] packetArray = PacketToArray(packet); 

     target.networkStream.Write(packetArray, 0, packetArray.Length); 
     target.networkStream.Flush(); 
     OnSend(packet); 
    } 

    private static void Listen() 
    { 
     tcpServer.Start(); 

     while (true) 
     { 
      try 
      { 
       Client client = new Client(); 
       client.tcpClient = tcpServer.AcceptTcpClient(); 
       client.networkStream = client.tcpClient.GetStream(); 
       client.thread = new Thread(new ParameterizedThreadStart(HandleCommunication)); 

       clients.Add(client); 
       client.thread.Start(client); 
       OnJoin(client); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine("Exception: " + ex.Message); 
       break; 
      } 
     } 
    } 

    private static void HandleCommunication(object client) 
    { 
     Client handleClient = (Client) client; 

     byte[] messageBuffer = new byte[4096]; 
     int bytesRead = 0; 

     while (true) 
     { 
      bytesRead = 0; 

      try 
      { 
       bytesRead = handleClient.networkStream.Read(messageBuffer, 0, messageBuffer.Length); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine("Exception: " + ex.Message); 
       break; 
      } 

      if (bytesRead == 0) 
      { 
       clients.Remove(handleClient); 
       OnLeave(handleClient); 
       break; 
      } 

      Packet packet = ArrayToPacket(messageBuffer); 
      OnReceive(packet); 
     } 
    } 

    private static void OnStart() 
    { 
     Console.WriteLine("Server started on port ."); 
    } 

    private static void OnJoin(Client client) 
    { 
     Console.WriteLine("Client [ID] connected."); 

     Send(client, PacketGenerator.Generate(OpCodes.opHandshake, null)); 
    } 

    private static void OnLeave(Client client) 
    { 
     Console.WriteLine("Client [ID] disconnected."); 
    } 

    private static void OnSend(Packet packet) 
    { 
     Console.WriteLine("Server: " + packet.opcode.ToString() + " | " + packet.message); 
    } 

    private static void OnReceive(Packet packet) 
    { 
     Console.WriteLine("Client [ID]: " + packet.opcode.ToString() + " | " + packet.message); 
    } 

    public struct Client 
    { 

     public TcpClient tcpClient; 
     public NetworkStream networkStream; 
     public Thread thread; 

    } 

} 

而这里的客户端代码:

[Serializable] 
public struct Packet 
{ 

    public int opcode; 
    public string message; 

} 

public static class Client 
{ 

    private static IPEndPoint endPoint; 

    private static TcpClient tcpClient; 
    private static NetworkStream networkStream; 
    private static Thread threadCommunication; 

    private static ASCIIEncoding encoding; 

    public static void Initialize(string ipAddress, int port) 
    { 
     endPoint = new IPEndPoint(IPAddress.Parse(ipAddress), port); 
     tcpClient = new TcpClient(); 
     networkStream = null; 
     threadCommunication = new Thread(new ThreadStart(HandleCommunication)); 

     encoding = new ASCIIEncoding(); 
    } 

    public static void Connect() 
    { 
     tcpClient.Connect(endPoint); 
     threadCommunication.Start(); 
     Console.WriteLine("Connected to server."); 

     networkStream = tcpClient.GetStream(); 
    } 

    public static byte[] PacketToArray(Packet packet) 
    { 
     IFormatter formatter = new BinaryFormatter(); 
     MemoryStream stream = new MemoryStream(); 

     formatter.Serialize(stream, packet); 
     byte[] packetArray = stream.GetBuffer(); 

     stream.Close(); 

     return packetArray; 
    } 

    public static Packet ArrayToPacket(byte[] array) 
    { 
     IFormatter formatter = new BinaryFormatter(); 
     MemoryStream stream = new MemoryStream(array); 

     Packet packet = new Packet(); 
     packet = (Packet)formatter.Deserialize(stream); 

     stream.Close(); 

     return packet; 
    } 

    public static void Send(Packet packet) 
    { 
     byte[] packetArray = PacketToArray(packet); 

     networkStream.Write(packetArray, 0, packetArray.Length); 
     networkStream.Flush(); 
     OnSend(packet); 
    } 

    private static void HandleCommunication() 
    { 
     byte[] messageBuffer = new byte[4096]; 
     int bytesRead = 0; 

     while (true) 
     { 
      bytesRead = 0; 

      try 
      { 
       bytesRead = networkStream.Read(messageBuffer, 0, messageBuffer.Length); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine("Exception: " + ex.Message); 
       break; 
      } 

      if (bytesRead == 0) 
      { 
       Console.WriteLine("Connection closed."); 
       break; 
      } 

      Packet packet = ArrayToPacket(messageBuffer); 
      OnReceive(packet); 
     } 
    } 

    private static void OnSend(Packet packet) 
    { 
     Console.WriteLine("Client [ID]: " + packet.opcode.ToString() + " | " + packet.message); 
    } 

    private static void OnReceive(Packet packet) 
    { 
     Console.WriteLine("Server: " + packet.opcode.ToString() + " | " + packet.message); 

     switch (packet.opcode) 
     { 

      case OpCodes.opHandshake: 
       Send(PacketGenerator.Generate(OpCodes.opHandshake, null)); 
       break; 

     } 
    } 

} 

但是当我从服务器发送一个数据包发送到客户端(握手)客户端得到的“packet =(Packet)formatter.Deserialize(stream)”中的“ArrayToPacket”函数中的例外;“ 确切的消息是:无法找到程序集“ComDee,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null”。 (ComDee是服务器运行的程序集)。

为什么?客户端的数据包结构与服务器的结构相同。

UPDATE

我编辑的服务器和客户端类,并使用protobuf网。 但客户端类中的“OnReceive”未被调用。 问题在哪里? 服务器级:

[ProtoContract] 
public struct Packet 
{ 

    [ProtoMember(1)] public int opcode; 
    [ProtoMember(2)] public string message; 

} 

public static class Server 
{ 

    private static IPEndPoint endPoint; 

    private static TcpListener tcpServer; 
    private static List<Client> clients; 
    private static Thread threadListen; 

    private static ASCIIEncoding encoding; 

    public static void Initialize(IPAddress allowedIPAddress, int port) 
    { 
     endPoint = new IPEndPoint(allowedIPAddress, port); 

     tcpServer = new TcpListener(endPoint); 
     clients = new List<Client>(); 
     threadListen = new Thread(new ThreadStart(Listen)); 

     encoding = new ASCIIEncoding(); 
    } 

    public static void Start() 
    { 
     threadListen.Start(); 
    } 

    public static byte[] PacketToArray(Packet packet) 
    { 
     IFormatter formatter = new BinaryFormatter(); 
     MemoryStream stream = new MemoryStream(); 

     Serializer.Serialize<Packet>(stream, packet); 
     byte[] packetArray = stream.GetBuffer(); 

     stream.Close(); 

     return packetArray; 
    } 

    public static Packet ArrayToPacket(byte[] array) 
    { 
     IFormatter formatter = new BinaryFormatter(); 
     MemoryStream stream = new MemoryStream(array); 

     Packet packet = new Packet(); 
     packet = Serializer.Deserialize<Packet>(stream); 

     stream.Close(); 

     return packet; 
    } 

    public static void Send(Client target, Packet packet) 
    { 
     byte[] packetArray = PacketToArray(packet); 

     target.networkStream.Write(packetArray, 0, packetArray.Length); 
     target.networkStream.Flush(); 
     OnSend(packet); 
    } 

    private static void Listen() 
    { 
     tcpServer.Start(); 
     OnStart(); 

     while (true) 
     { 
      try 
      { 
       Client client = new Client(); 
       client.tcpClient = tcpServer.AcceptTcpClient(); 
       client.networkStream = client.tcpClient.GetStream(); 
       client.thread = new Thread(new ParameterizedThreadStart(HandleCommunication)); 

       clients.Add(client); 
       client.thread.Start(client); 
       OnJoin(client); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine("Exception: " + ex.Message); 
       break; 
      } 
     } 
    } 

    private static void HandleCommunication(object client) 
    { 
     Client handleClient = (Client) client; 

     byte[] messageBuffer = new byte[4096]; 
     int bytesRead = 0; 

     while (true) 
     { 
      bytesRead = 0; 

      try 
      { 
       bytesRead = handleClient.networkStream.Read(messageBuffer, 0, messageBuffer.Length); 
      } 
      catch 
      { 
       clients.Remove(handleClient); 
       OnLeave(handleClient); 
       break; 
      } 

      if (bytesRead == 0) 
      { 
       Packet packet = ArrayToPacket(messageBuffer); 
       OnReceive(packet); 
      } 
     } 
    } 

    private static void OnStart() 
    { 
     Console.WriteLine("Server started."); 
    } 

    private static void OnJoin(Client client) 
    { 
     Console.WriteLine("Client [ID] connected."); 

     Send(client, PacketGenerator.Generate(OpCodes.opHandshake, null)); 
    } 

    private static void OnLeave(Client client) 
    { 
     Console.WriteLine("Client [ID] disconnected."); 
    } 

    private static void OnSend(Packet packet) 
    { 
     Console.WriteLine("Server: " + packet.opcode.ToString() + " | " + packet.message); 
    } 

    private static void OnReceive(Packet packet) 
    { 
     Console.WriteLine("Client [ID]: " + packet.opcode.ToString() + " | " + packet.message); 
    } 

    public struct Client 
    { 

     public TcpClient tcpClient; 
     public NetworkStream networkStream; 
     public Thread thread; 

    } 

} 

这里是客户类别:

[ProtoContract] 
public struct Packet 
{ 

    [ProtoMember(1)] 
    public int opcode; 
    [ProtoMember(2)] 
    public string message; 

} 

public static class Client 
{ 

    private static IPEndPoint endPoint; 

    private static TcpClient tcpClient; 
    private static NetworkStream networkStream; 
    private static Thread threadCommunication; 

    private static ASCIIEncoding encoding; 

    public static void Initialize(string ipAddress, int port) 
    { 
     endPoint = new IPEndPoint(IPAddress.Parse(ipAddress), port); 
     tcpClient = new TcpClient(); 
     networkStream = null; 
     threadCommunication = new Thread(new ThreadStart(HandleCommunication)); 

     encoding = new ASCIIEncoding(); 
    } 

    public static void Connect() 
    { 
     tcpClient.Connect(endPoint); 
     threadCommunication.Start(); 
     Console.WriteLine("Connected to server."); 

     networkStream = tcpClient.GetStream(); 
    } 

    public static byte[] PacketToArray(Packet packet) 
    { 
     IFormatter formatter = new BinaryFormatter(); 
     MemoryStream stream = new MemoryStream(); 

     Serializer.Serialize<Packet>(stream, packet); 
     byte[] packetArray = stream.GetBuffer(); 

     stream.Close(); 

     return packetArray; 
    } 

    public static Packet ArrayToPacket(byte[] array) 
    { 
     IFormatter formatter = new BinaryFormatter(); 
     MemoryStream stream = new MemoryStream(array); 

     Packet packet = new Packet(); 
     packet = Serializer.Deserialize<Packet>(stream); 

     stream.Close(); 

     return packet; 
    } 

    public static void Send(Packet packet) 
    { 
     byte[] packetArray = PacketToArray(packet); 

     networkStream.Write(packetArray, 0, packetArray.Length); 
     networkStream.Flush(); 
     OnSend(packet); 
    } 

    private static void HandleCommunication() 
    { 
     byte[] messageBuffer = new byte[4096]; 
     int bytesRead = 0; 

     while (true) 
     { 
      bytesRead = 0; 

      try 
      { 
       bytesRead = networkStream.Read(messageBuffer, 0, messageBuffer.Length); 
      } 
      catch 
      { 
       Console.WriteLine("Connection closed."); 
       break; 
      } 

      if (bytesRead == 0) 
      { 
       Packet packet = ArrayToPacket(messageBuffer); 
       OnReceive(packet); 
      } 
     } 
    } 

    private static void OnSend(Packet packet) 
    { 
     Console.WriteLine("Client [ID]: " + packet.opcode.ToString() + " | " + packet.message); 
    } 

    private static void OnReceive(Packet packet) 
    { 
     Console.WriteLine("Server: " + packet.opcode.ToString() + " | " + packet.message); 

     switch (packet.opcode) 
     { 

      case OpCodes.opHandshake: 
       Send(PacketGenerator.Generate(OpCodes.opHandshake, null)); 
       break; 

     } 
    } 

} 
+0

您的读者在调用'ArrayToPacket'之前需要一直读取,直到它获得一个零或错误。否则,你试图解析整个消息的片段。 –

+0

对不起,我在tcp编程方面比较新。 如何检查阅读是否完整? – namespace

+0

您的发送逻辑似乎是“我编码消息,发送消息,然后关闭连接”。如果是这样,匹配的接收逻辑是“我一直在接收,直到连接关闭,然后我将收到的所有内容解析为单个消息”。但是您的收到代码不会这样做。请参阅[这个答案](http://stackoverflow.com/a/14715497/721269)来学习更大,更重要的课程。 –

回答

3

类型由它们组装作用域和BinaryFormatter的序列化类型的元数据(程序集限定名称等)。在两个地方有相同的class的副本是不够的:它们不是相同的类型除非它们来自相同的程序集

另请注意,BinaryFormatter在存储线路上相当详细。如果你想要的东西,解决了这两个问题,而你需要做的所有的系列化手动,然后protobuf网将帮助:

  • 它是
  • 它不绑定到特定类型的线非常密集;你可以用一个序列只要A和B类似于

例如为B反序列化:

[ProtoContract] 
public struct Packet {  
    [ProtoMember(1)] public int opcode; 
    [ProtoMember(2)] public string message; 
} 

,并使用Serializer.Serialize代替BinaryFormatter

+0

'Serializer'从哪里来? – AkariKamigishi