通过套接字或tcp发送类对象列表

时间:2013-08-13 15:44:24

标签: c# list class sockets object

我正在尝试将对象列表发送到另一台计算机。我是套接字的新手,但我已经尝试了很多东西。最后,我总是遇到错误,无法克服错误。

我发送的对象列表是包含函数,变量和属性的类。我已将[Serializable]放在此类的顶部。

每次客户端执行某个操作时,它都会将San_Change更改为true并启动客户端线程。

我已在下面附上我的代码,我们将不胜感激。

        public void Create_Network_Thread(string Host_Or_Client)
    {
        //This creates a network thread and starts it.

        //Host
        if (Host_Or_Client == "Host")
        {
            Host_networkThread = new Thread(new ThreadStart(Host_Network_Thread_Start));
            Host_networkThread.Start();
        }
        //Client
        else
        {
            Client_networkThread = new Thread(new ThreadStart(Client_Network_Thread_Start));
            Client_networkThread.Start();
        }
    }


    private void Host_Network_Thread_Start()
    {

        try
        {
            TcpListener serverSocket = new TcpListener(8888);
            TcpClient clientSocket = default(TcpClient);

            serverSocket.Start();

            clientSocket = serverSocket.AcceptTcpClient();

            while (true)
            {
                object San_Object;

                NetworkStream networkStream = clientSocket.GetStream();

                byte[] bytesFrom = new byte[clientSocket.Available];

                networkStream.Read(bytesFrom, 0, clientSocket.Available);

                San_Object = ByteArrayToObject(bytesFrom);

                San_List = (List<San>)San_Object;



                byte[] sendBytes = ObjectToByteArray(San_Object);

                networkStream.Write(sendBytes, 0, sendBytes.Length);

                networkStream.Flush();
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }



    private void Client_Network_Thread_Start()
    {
        while (true)
        {
            if (San_Change == true)
            {
                San_Change = false;

                try
                {
                    System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient();

                    object San_Object = San_List;

                    string cur_ip = "";

                    clientSocket.Connect(cur_ip, 8888);

                    NetworkStream serverStream = clientSocket.GetStream();

                    byte[] outStream = ObjectToByteArray(San_Object);

                    serverStream.Write(outStream, 0, outStream.Length);

                    serverStream.Flush();


                    byte[] inStream = new byte[(int)clientSocket.ReceiveBufferSize];

                    San_Object = ByteArrayToObject(inStream);

                    San_List = (List<San>)San_Object;
                }

                catch (Exception e)
                {

                    Console.WriteLine(e.ToString());
                }
            }
        }
    }

    private byte[] ObjectToByteArray(Object obj)
    {
        if (obj == null)
            return null;
        BinaryFormatter bf = new BinaryFormatter();
        MemoryStream ms = new MemoryStream();
        bf.Serialize(ms, obj);
        return ms.ToArray();
    }

    private Object ByteArrayToObject(byte[] arrBytes)
    {
        MemoryStream memStream = new MemoryStream();
        BinaryFormatter binForm = new BinaryFormatter();
        memStream.Write(arrBytes, 0, arrBytes.Length);
        memStream.Seek(0, SeekOrigin.Begin);
        Object obj = (Object)binForm.Deserialize(memStream);
        return obj;
    }

}

当发生这种情况时:

忘了添加它,但是当我运行它时,因为代码失败了。这是信息,希望这会有所帮助。再次感谢。

e   {System.Runtime.Serialization.SerializationException: Binary stream '0' does not contain a valid BinaryHeader. Possible causes are invalid stream or object version change between serialization and deserialization.
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
   at San_Player_V2.Game.ByteArrayToObject(Byte[] arrBytes) in San_Player_V2\Game.cs:line 573
   at San_Player_V2.Game.Client_Network_Thread_Start() in San_Player_V2\Game.cs:line 477}   System.Exception {System.Runtime.Serialization.SerializationException}

3 个答案:

答案 0 :(得分:2)

通常的问题:

  • 不处理Read
  • 的返回值
  • 认为可用字节代表完整的数据单元
  • 缺乏逻辑框架(通常通过长度前缀)

我个人也会说使用BinaryFormatter是有问题的,但这不是最大的问题。

请参阅http://marcgravell.blogspot.com/2013/02/how-many-ways-can-you-mess-up-io.html

答案 1 :(得分:0)

这似乎是你双重工作/重新发明轮子,那就是:

  
      
  1. 将对象转换为字节数组
  2.   
  3. 你通过流发送出来。
  4.   

相反,你尝试这样的事情:

  
      
  1. 将您的套接字链接到ObjectOutputStream
  2.   
  3. 使用ObjectOutputStream直接编写对象并使用标准API
  4.   

处理序列化末尾的对象并在另一端反序列化它(当你使用ObjectInputStream接收它时)。

答案 2 :(得分:0)

所以我认为我找到了答案。什么是将对象转换为xml然后将该xml转换为字符串。将该字符串作为字符串发送到套接字然后在另一端将其重新转换为xml然后再返回到对象。我附上了一个小例子。

这是在对象中并调用xml它。

        public string ToXML()
    {
        var stringwriter = new System.IO.StringWriter();
        var serializer = new XmlSerializer(this.GetType());
        serializer.Serialize(stringwriter, this);
        return stringwriter.ToString();
    }

调用此方法将xml转换回选择对象。

    public static Object_Name_Here LoadFromXMLString(string xmlText)
    {
        var stringReader = new System.IO.StringReader(xmlText);
        var serializer = new XmlSerializer(typeof(Object_Name_Here));
        return serializer.Deserialize(stringReader) as Object_Name_Here;
    }

如果有人有更好的想法,那就是我正在做的事情请分享一个好榜样。

谢谢!