小弟近来使用C#中的TCPClient和NetStream传输类对象。在传输的时候使用到了序列化和反序列化。问题是这样。经测试,小弟在本地可以完成序列化和反序列化,不过传输到其他计算机之后就不能完成反序列化。代码是这样的。求救啊!//序列化类对象
        static public byte[] Serialize(object obj)
        {
            BinaryFormatter binaryF = new BinaryFormatter();
            MemoryStream ms = new MemoryStream();
            binaryF.Serialize(ms, obj);
            ms.Seek(0, SeekOrigin.Begin);
            byte[] buffer = new byte[(int)ms.Length];
            ms.Read(buffer, 0, buffer.Length);
            ms.Close();
            return buffer;
        }
        //反序列化类对象
        static public object Deserialize(byte[] buffer)
        {
            BinaryFormatter binaryF = new BinaryFormatter();
            MemoryStream ms = new MemoryStream(buffer, 0, buffer.Length, false);
            object pag = binaryF.Deserialize(ms);
            ms.Close();
            return pag;
        }//客户端向服务器发送连接请求
                TcpClient client = connectToServer();
                NetworkStream clientstream = client.GetStream();
                Package pag = new Package();
                pag.flag = 1;
                pag.player_name = txt_name.Text;
                buffer = Serialize((object)pag);
                Package p = new Package();
                p = Deserialize(buffer) as Package;
                for (j = 0; j < buffer.Length; j++)
                {
                    requestbuffer[j] = buffer[j];
                }
                requestbuffer[j] = (byte)'#';
                clientstream.Write(requestbuffer, 0, requestbuffer.Length);//服务端接收数据
 byte[] requestbuffer = new byte[bufferSize];
            byte[] responsebuffer = new byte[bufferSize];
            int readBytes = 0;
            int i;
            readBytes = clientstream.Read(requestbuffer, 0, bufferSize);
            for (i = 0; i < requestbuffer.Length; i++) {
                if (requestbuffer[i] == '#') {
                    break;
                }
            }
            byte[] buffer = new byte[i];
            for (int j = 0; j < buffer.Length; j++) {
                buffer[j] = requestbuffer[j];
            }
            
            Package clientpackage = new Package();
            clientpackage = Deserialize(buffer) as Package;
代码执行到clientpackage = Deserialize(buffer) as Package;时,在反序列化函数中的
object pag = binaryF.Deserialize(ms);报错----输入流是无效的二进制格式。开始内容(以字节为单位)是: 01-00-00-00-06-03-00-00-00-06-77-61-6E-67-6C-66-09...可是在本地机上也是这个二进制串,能够反序列化啊?求救是怎么回事?在线等啊!

解决方案 »

  1.   

    找到问题了,是序列化的时候把客户端项目空间序列化进去了。服务端反序列化的时候找不到相关程序集。各位大侠们,这种情况怎么办啊?这是我序列化和反序列化的代码。 //序列化类对象
            static public byte[] Serialize(object obj)
            {
                BinaryFormatter binaryF = new BinaryFormatter();
                MemoryStream ms = new MemoryStream();
                binaryF.Serialize(ms, obj);
                ms.Seek(0, SeekOrigin.Begin);
                byte[] buffer = new byte[(int)ms.Length];
                ms.Read(buffer, 0, buffer.Length);
                ms.Close();
                return buffer;
            }
            //反序列化类对象
            static public object Deserialize(byte[] buffer)
            {
                 binaryF = new BinaryFormatter();
                MemoryStream ms = new MemoryStream(buffer, 0, buffer.Length, false);
                object pag = binaryF.Deserialize(ms);
                ms.Close();
                return pag;
            }
    谁能给个解决方法啊?最好能指点下代码的!拜托啊!
      

  2.   

    嗯,同意五楼的
    我就是这样做的,下面部分单独出来生成dll,两边都引用,代码如下using System;
    using System.Collections.Generic;
    using System.Collections;
    using System.Text;
    using System.Xml.Serialization;
    using System.IO.Compression;
    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;
    namespace CommonClassLib
    {
        [Serializable()]
        public class ChangeRecord
        {
            /// <summary>
            /// 主键
            /// </summary>
            public string Guid { get; set; }
            /// <summary>
            /// 表名
            /// </summary>
            public string TableName { get; set; }
            /// <summary>
            /// 表中主键名
            /// </summary>
            public string PKFieldName { get; set; }
            /// <summary>
            /// 同步记录id
            /// </summary>
            public string SyncronId { get; set; }
            /// <summary>
            /// 操作类型:1增2删3改
            /// </summary>
            public string Operate { get; set; }
            /// <summary>
            /// 记录处理状态
            /// </summary>
            public string State { get; set; }
            /// <summary>
            /// 变化触发时间
            /// </summary>
            public DateTime TriggTime { get; set; }
        }    [Serializable]
        public class MyList<T> : List<T>
        {    }    [Serializable]
        public class KVPair
        {
            public string Field { get; set; }
            public string Value { get; set; }
        }    /// <summary>
        /// 二进制序列化
        /// </summary>
        public class SerializableObj<T> where T : IEnumerable
        {
            public static Byte[] Serialize(T obj)
            {
                try
                {
                    MemoryStream ms = new MemoryStream();
                    BinaryFormatter bf = new BinaryFormatter();
                    bf.Serialize(ms, obj);
                    ms.Position = 0;
                    byte[] buffers = ms.ToArray();
                    ms.Close();
                    ms.Dispose();
                    return Compress(buffers);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }        public static byte[] Compress(byte[] buffer)
            {
                MemoryStream ms = new MemoryStream();
                GZipStream gzip = new GZipStream(ms, CompressionMode.Compress, true);
                //byte[] returnBuffer=new byte [];
                gzip.Write(buffer, 0, buffer.Length);
                gzip.Close();
                ms.Position = 0;
                byte[] rebuffer = new byte[ms.Length];
                ms.Read(rebuffer, 0, int.Parse(ms.Length.ToString()));
                return rebuffer;
            }
        }    /// <summary>
        /// 二进制反序列化
        /// </summary>
        public class Deserizlize<T> where T : class, IEnumerable
        {
            public Deserizlize()
            {
                //
                // TODO: 在此处添加构造函数逻辑
                //
            }
            public static byte[] Decompress(byte[] buffer)
            {
                try
                {
                    MemoryStream ms = new MemoryStream(buffer);
                    ms.Position = 0;
                    GZipStream gzip = new GZipStream(ms, CompressionMode.Decompress);
                    byte[] rebuffer = new byte[100];
                    MemoryStream msre = new MemoryStream();
                    int readcont = gzip.Read(rebuffer, 0, rebuffer.Length);
                    while (readcont > 0)
                    {
                        msre.Write(rebuffer, 0, readcont);
                        readcont = gzip.Read(rebuffer, 0, rebuffer.Length);
                    }
                    return msre.ToArray();
                }
                catch (Exception ex)
                {                throw ex;
                }
            }        public static T Deserilize(byte[] buffer)
            {
                try
                {
                    byte[] debuffer = Decompress(buffer);
                    BinaryFormatter bf = new BinaryFormatter();
                    MemoryStream ms = new MemoryStream(debuffer);
                    ms.Position = 0;
                    T obj = bf.Deserialize(ms) as T;
                    return obj;
                }
                catch (Exception ex)
                {                throw ex;
                }
            }
        }
    }
      

  3.   


     BinaryFormatter brFormatter = new BinaryFormatter();
     //二进制序列化的时候,有个借口,下面的
     brFormatter.Binder = new ConvertAssemblyBinder();/// <summary>
        /// 控制将序列化对象绑定到类型的过程
        /// </summary>
        public sealed class ConvertAssemblyBinder : SerializationBinder
        {
            /// <summary>
            /// 控制二进制序列化类型转换
            /// </summary>
            /// <param name="assemblyName"></param>
            /// <param name="typeName"></param>
            /// <returns></returns>
            // 在序列化过程中,格式化程序传输创建正确类型和版本的对象的实例所需的信息。
            // 此信息通常包括对象的完整类型名称和程序集名称。
            // 程序集名称包含程序集的名称、版本和强名称(请参见具有强名称的程序集)散列。
            // 默认情况下,反序列化将使用此信息创建等同对象的实例(安全策略所限制的任何程序集加载属于例外)。
            // 因为类已经在程序集之间移动或者因为在服务器和客户端上要求类的不同版本,有些用户需要控制要加载哪些类。
            // 这是一个抽象基类。所有联编程序都扩展此类。
            // 给继承者的说明 从 SerializationBinder 继承时,必须重写以下成员:BindToType。         // 由于服务器和客户端共同使用同一个类型,进行数据传递,但是服务器和客户端的同一类型处于不同的
            // 程序集,需要在反序列化的时候,提供强制类型转换
            public override Type BindToType(string assemblyName, string typeName)
            {
                // 取得当前的程序集名称,取得传递过来,类型名称不修改,都是"TestPro.CSFTcpMsg"
                string strCurAssembly = Assembly.GetExecutingAssembly().FullName;            // 返回当前对应的类型
                Type CurType = Type.GetType(String.Format("{0}, {1}", typeName, strCurAssembly));
                return CurType;
            }
        }
      

  4.   

    如果使用binder获取程序集名称的话,能不能给个序列化和发序列化的代码学习一下啊!??在线等啊!
      

  5.   

    5,6楼同学,请问如何做成公共类库啊?小弟新接触C#时间不久啊?求指点啊!
    其实就是新建一个class Library的项目,把公共的东西放在里边,在其他项目中添加对此项目的引用罢了
      

  6.   


    照抄。。只要让BindToType()方法返回你现在的程序集+命名空间序列化类名就可以了。我服务器有个消息类:CSFTcpMsg,但是命名空间是:TcpTestPro.CSFTcpMsg
    客户端有个消息类:CSFTcpMsg,但是命名空间是:TestPro.CSFTcpMsg
    CSFTcpMsg类定义在服务器端和客户端都是一致的,但是不属于同一命名空间,也不是同一程序集
    客户端收到后,反序列化一定会检测程序集信息,不是就报错了
      

  7.   

    比较方便于网络软件的做法是使用xml或者json序列化,而不是二进制序列化。比如说现实情况下有1个服务器端、1000个客户端,那么客户端可能有各种软件版本并不是总能统一升级为一个版本的程序,而且服务器也可能随时重新编译新的版本,因此二进制序列化不利于升级和维护。使用xml、json,就算传递一个对象时在一端的程序中的这个类型有10个字段,而另一端程序中的这个类型只有9个字段,也可以正确地通讯,所以利于升级和维护。
      

  8.   

    另外对于json序列化,就算两边的对象类型名称完全不同,比如你把一个“坦克”对象序列化了然后传给对方反序列为“轮船”对象,json也是可以序列化的。它并不纠结于类型的名字或者命名空间,而是看看序列化时的哪些属性可以反序列化到目标对象上,就仅仅反序列这些属性。所以json的方便程度比xml更强。另外,json序列化/反序列化的速度基本上跟二进制序列化相同,远远大于xml数倍,而且也更短小、可读性也不太差。所以使用json序列化方法,优于使用xml序列化,也优于使用二进制序列化。(唯一的就是对于byte[]类型的序列化比较差劲,如果可能需要我们自己先将byte[]进行base64编码)。
      

  9.   

    楼上说的很对,二进制序列化很难跨越平台。
    唯一的优点就是体积小,如果楼主采用文本序列化就不存在这样的问题了
    这个给你:
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary;序列化的方式,6楼的方法已经很标准了
    我的代码:我以前也用文本序列化的/// <summary>
            /// 反序列化TcpMessage对象
            /// </summary>
            /// <param name="Msg"></param>
            /// <returns></returns>
            //  采用二进制序列化取代了XML序列化,二进制体积小,速度快,但是有一定的限定条件
            public static TcpMsg GetMessage_(byte[] Msg)
            {
                try
                {
                    using (MemoryStream memStream = new MemoryStream(Msg))
                    {
                        BinaryFormatter brFormatter = new BinaryFormatter();
                        brFormatter.Binder = new ConvertAssemblyBinder();
                        TcpMsg tm = (TcpMsg)brFormatter.Deserialize(memStream);                    //XmlSerializer xs = new XmlSerializer(typeof(TcpMsg));
                        //TcpMsg tm        = xs.Deserialize(memStream) as TcpMsg;
                        return tm;
                    }
                }
                catch (Exception)
                {
                    return null;
                }
            }
      

  10.   

    谢谢各位大侠们!最后问题得到了解决。解决办法如下:
    http://topic.csdn.net/u/20100428/21/d36073ab-5731-4259-bb37-876ae154ad45.html结贴散分!谢谢你们的热心帮助!感激不尽!!