socket中将对象转化为字节发送

本文展示了如何在C#中利用BinaryFormatter将一个可序列化的类对象`MyClass`转换成字节数组。通过创建一个实例,设置其属性,并通过`ObjectToBytes`方法进行序列化,生成的字节数组长度与对象字段的长度有关。这个过程对于通过socket传输对象数据至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      通过socket来发送信息的时候,它只接受byte[]类型的参数,怎么样把一个对象转为byte[],之后将它通过socket发送呢?
      前段时间测试一个P2P程序,通过UDP来发送数据。UdpClient.Send(..)方法需要一个byte[]这样的参数。想当年用c++Builder的时候,只需要用强制转换就行了。如今时过境迁,.net平台上处理这事却似乎有些麻烦!今天恰好在csdn上见一帖,又看到了另一种处理方法,^_^, 现将我所知的3种方法总结一下。

    一、通过序列化将对象转为byte[], 之后再反序化为对象
     public   class  P2PHelper
    
{        /// <summary>
        
/// 将一个object对象序列化,返回一个byte[]
        
/// </summary>
        
/// <param name="obj">能序列化的对象</param>
        
/// <returns></returns>

        public static byte[] ObjectToBytes(object obj)
        
{
            
using (MemoryStream ms = new MemoryStream())
            
{
                IFormatter formatter 
= new BinaryFormatter();
                formatter.Serialize(ms, obj);
                
return ms.GetBuffer();
            }

        }


        
/// <summary>
        
/// 将一个序列化后的byte[]数组还原
        
/// </summary>
        
/// <param name="Bytes"></param>
        
/// <returns></returns>

        public static object BytesToObject(byte[] Bytes)
        
{
            
using (MemoryStream ms = new MemoryStream(Bytes))
            
{
                IFormatter formatter 
= new BinaryFormatter();
                
return formatter.Deserialize(ms);
            }

        }


    }
       这种方法通过序列化来处理对象,虽然简单,然后每一个对象序列化后都至少有256字节, 会导致网络流量的增大。想想,如果一个对象只有10个字节,然而发送的时候却有256字节~~~~~~恐怖(注:多谢 双鱼座 的指正)

        二、使用BitConvert类来处理
       很麻烦的一种方法,我这等懒人是不敢用这种方法的了。不过这篇文章 http://pierce.cnblogs.com/archive/2005/06/21/178343.aspx 上有些讲解,想了解的朋友可以去看看。

        三、使用Unsafe方式
       先看代码(尚不知是否有memory  leak!!!):
     class   Test
    
{
        
public static unsafe  byte[] Struct2Bytes(Object obj)
        
{
            
int size = Marshal.SizeOf(obj);
            
byte[] bytes = new byte[size];
            
fixed(byte* pb = &bytes[0])
            
{
                Marshal.StructureToPtr(obj,
new IntPtr(pb),true);
            }

            
return bytes;
        }


        
public static unsafe Object Bytes2Struct(byte[] bytes)
        
{
            
fixed(byte* pb = &bytes[0])
            
{
                
return Marshal.PtrToStructure(new IntPtr(pb), typeof(Data));
            }

        }

    }
      这种方法的确不错,即不增加网络流量,处理起来也简单。只是,似乎它只能处理Struct, 对于Class就有麻烦了。(注:请查看 sunmast  的评论)

      倘若还有其它方法,请告之,:)

posted on 2005-07-23 20:58 楚潇 阅读(1190) 评论(12)   编辑  收藏 收藏至365Key 所属分类: .net技术

评论:
#  re: 将对象转为byte[] 2005-07-23 21:16 | 浮云
我用的第二种方法。虽然麻烦点,不过最灵活。
  
#  re: 将对象转为byte[] 2005-07-23 22:19 | 萧寒
我原来做过工控的程序,通讯要转化double/string/int 的为byte进行通讯;实现和你的方法三一样,采用指针;这里可以看到原文; http://chinasf.cnblogs.com/archive/2005/05/28/163932.html
但使用BitConvert类来处理会更简单.
  
#  re: 将对象转为byte[] 2005-07-23 22:48 | 楚潇
楼上,你的方法跟方法3不一样吧,我列的方法3可以可任何struct转为byte[]

  
#  re: 将对象转为byte[] 2005-07-24 03:12 | 双鱼座
标准的方法就是方法一。

然后每一个对象序列化后都至少有1K, 会导致网络流量的增大。想想,如果一个对象只有10个字节,然而发送的时候却有1K~~~~~~恐怖

对此我非常质疑。如果对象真的只占10个字节的话,肯定只有256字节。BinaryFormatter使用空间是成倍增长的,当实际占用需要大于256字节时,为512字节;当实际占用需要大于512字节时,为1024字节;然后是2048、4096....依次类推。
除了一个文本的用于描述程序集名、类型名和字段名的内容外,所占用的空间是实际所需的。

如果楼主想节省字节,有两个方案:
最好的方法是采用标准的压缩方式将内容压缩,一般会非常小,甚至可能比实际占用的空间还要小。网上有大量开源的压缩类库可以使用。
如果嫌这个方法麻烦,有个方法更易于实现。就是数一数尾部有多少个0,清除这些0,补上一个字节的空间,写上多少个零就行了。不过这种方式省不了多少字节。

  
#  re: 将对象转为byte[] 2005-07-24 13:11 | Bruce
支持双鱼座的提法,第一种是标准。如果使用第二种方法,当对象很复杂的时候不是很惨...
  
#  re: 将对象转为byte[] 2005-07-24 13:43 | 楚潇
to 双鱼座 :

据我测试,无论我的对象有多少字段,反回的byte[]数组的Length属性都是1024, 而且,无论是用二进制还是xml来序列化对象到硬盘上的文件,都至少有1KB大小。(vs2003, .net 1.1)
  
#  re: 将对象转为byte[] 2005-07-24 14:46 | sunmast
你写的第三种方法是我最早发表在csdn论坛和blog上的
但是你有些误解,它对struct和class都可以处理

并且这里虽然有用到了unsafe代码,但是没有在CRT堆上分配内存,也没有用动态指针,并不会出现内存泄露

这个方法唯一的问题是类型必须能用Marshal.SizeOf得到大小(有些struct和有些class不行)
  
#  re: 将对象转为byte[] 2005-07-24 17:07 | 双鱼座
@楚潇:
我已经不知道如何说服你了。你可不可以相信MS的程序员都不是傻瓜?在Remoting中大量用到Serialization,难道他们从来不考虑减少网络流量的问题?
试试以下代码:

using System;
using System.Collections;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

[Serializable]
public class MyClass
{
 private string _Value;
 
 public string Value
 {
  get
  {
   return _Value;
  }
  set
  {
   _Value = value;
  }
 }
 
 public static void Main()
 {
  int[] lens = new int[] {100, 800, 1000, 3000, 6000, 10000};
  MyClass myClass = new MyClass();
  foreach (int len in lens)
  {
   myClass.Value = new string('z', len);
   byte[] buff = ObjectToBytes(myClass);
   WL("Field Length: {0}, Buffer Length: {1}", len, buff.Length);
  }
  RL();
 }
 
 public static byte[] ObjectToBytes(object obj)
 {
  using (MemoryStream ms = new MemoryStream())
  {
   IFormatter formatter = new BinaryFormatter();
   formatter.Serialize(ms, obj);
   return ms.GetBuffer();
  }
 }

 private static void WL(string text, params object[] args)
 {
  Console.WriteLine(text, args); 
 }
 
 private static void RL()
 {
  Console.ReadLine(); 
 }
 
 private static void Break()
 {
  System.Diagnostics.Debugger.Break();
 }
}

我没有用Visual studio.net,我是用SnippetCompiler编写的,相信在任何时候结果都是如此:
Field Length: 100, Buffer Length: 256
Field Length: 800, Buffer Length: 1024
Field Length: 1000, Buffer Length: 2048
Field Length: 3000, Buffer Length: 4096
Field Length: 6000, Buffer Length: 8192
Field Length: 10000, Buffer Length: 16384

  
#  re: 将对象转为byte[] 2005-07-24 19:14 | 楚潇
@双鱼座 :
还是你厉害,我刚才用C# 2005 Express测了一下, 你的对!不过前段时间用vs2k3测试一个P2P程序的时候,真的发现每次返回都是1024,看来是我没深入了解呀!

多谢你指正
  
#  re: 将对象转为byte[] 2005-07-25 08:59 | 张老三
最近刚在一项目中使用第一种方式, 还没测试流量了,
看了双鱼座的解释就放心了.
  
#  re: 将对象转为byte[] 2005-07-25 09:01 | James
.net framework还提供了NetworkStream,你为何不用?简单几行代码就把byte[]传输出去了
  
#  re: 将对象转为byte[] 2005-08-04 13:23 | lee
指定数组长度
using (MemoryStream ms = new MemoryStream())
{
IFormatter formatter = new BinaryFormatter();
formatter.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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值