简体   繁体   English

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

[英]Send a list of class objects through a socket or tcp

I'm trying to send a list of objects to another computer. 我正在尝试将对象列表发送到另一台计算机。 I'm new to sockets and such but have tried quite a few things. 我是套接字的新手,但我已经尝试了很多东西。 In the end I always end up with errors and can't get past them. 最后,我总是遇到错误,无法克服错误。

The list of objects I'm sending are classes with functions, variables and properties. 我发送的对象列表是包含函数,变量和属性的类。 I have placed the [Serializable] at the top of this class. 我已将[Serializable]放在此类的顶部。

Each time a client performs a certain action it will change the San_Change to true and start the client thread. 每次客户端执行某个操作时,它都会将San_Change更改为true并启动客户端线程。

I've attached my code below, and any help would be appreciated. 我已在下面附上我的代码,任何帮助将不胜感激。

        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;
    }

}

When ran this occurs: 运行时发生这种情况:

Forgot to add this in, but when I run this as it is the code fails. 忘了添加它,但当我运行它时,因为它是代码失败。 Here is the information, hope this helps. 这是信息,希望这会有所帮助。 Thanks again. 再次感谢。

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}

The usual problems: 通常的问题:

  • not processing the return value of Read 不处理Read的返回值
  • thinking that the available-bytes represents complete units of data 认为可用字节代表完整的数据单元
  • the lack of logical framing (usually via a length-prefix) 缺乏逻辑框架(通常通过长度前缀)

Personally I'd also say that using BinaryFormatter is problematic, but that isn't the biggest issue. 我个人也说使用BinaryFormatter是有问题的,但这不是最大的问题。

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

It seems to be that you're double double work/reinventing the wheel here, that is: 这似乎是你双重工作/重新发明轮子,那就是:

  1. You convert an object to a byte array 您将对象转换为字节数组
  2. You send it out through the stream. 你通过流发送出去。

How about instead you try something like that: 相反,你尝试这样的事情:

  1. Chain your Socket to an ObjectOutputStream 将您的Socket链接到ObjectOutputStream
  2. Use the ObjectOutputStream to write the object out directly and let the standard APIs 使用ObjectOutputStream直接编写对象并使用标准API

handle serializing the object on your end and deserializing it on the other end (when you use ObjectInputStream to receive it). 处理序列化您的对象并在另一端反序列化它(当您使用ObjectInputStream接收它时)。

So I think that I found my answer. 所以我认为我找到了答案。 What is convert the object to an xml then convert that xml to a string. 什么是将对象转换为xml然后将该xml转换为字符串。 send that string through the socket just as a string then on the other side reconvert it to xml then back to a object. 将该字符串作为字符串发送到套接字然后在另一端将其重新转换为xml然后再返回到对象。 I've attached a small example. 我附上了一个小例子。

This is in the object and called to xml it. 这是在对象中并调用xml它。

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

This is called to convert the xml back to the object of your pick. 调用此方法可将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;
    }

That is what I'm doing if someone has a better idea please share with a good example. 如果有人有更好的想法,那就是我正在做的事情请分享一个好榜样。

Thank you! 谢谢!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM