0

我正在尝试将对象列表发送到另一台计算机。我是套接字等的新手,但尝试了很多东西。最后,我总是以错误告终,无法超越。

我发送的对象列表是具有函数、变量和属性的类。我已将 [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}
4

3 回答 3

2

常见问题:

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

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

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

于 2013-08-13T15:54:17.550 回答
0

似乎您在这里双重工作/重新发明轮子,即:

  1. 您将对象转换为字节数组
  2. 您通过流将其发送出去。

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

  1. 将您的 Socket 链接到 ObjectOutputStream
  2. 使用 ObjectOutputStream 直接写出对象,让标准 API

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

于 2013-08-13T16:19:17.700 回答
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;
    }

这就是我正在做的事情,如果有人有更好的想法,请分享一个很好的例子。

谢谢!

于 2013-08-13T23:41:15.863 回答