using System; using System.Collections.Generic; using System.Linq; using System.Text; using HPSocketCS.SDK; using System.Runtime.InteropServices; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; namespace HPSocketCS { public class TcpAgentEvent { public delegate HandleResult OnConnectEventHandler(IntPtr connId /* IntPtr pClient */); public delegate HandleResult OnSendEventHandler(IntPtr connId, IntPtr pData, int length); public delegate HandleResult OnReceiveEventHandler(IntPtr connId, IntPtr pData, int length); public delegate HandleResult OnCloseEventHandler(IntPtr connId); public delegate HandleResult OnErrorEventHandler(IntPtr connId, SocketOperation enOperation, int errorCode); public delegate HandleResult OnShutdownEventHandler(); public delegate HandleResult OnPrepareConnectEventHandler(IntPtr connId /* IntPtr pClient */, uint socket); } public class TcpAgent { protected IntPtr _pAgent = IntPtr.Zero; protected IntPtr pAgent { get { //if (_pClient == IntPtr.Zero) //{ // throw new Exception("pClient == 0"); //} return _pAgent; } set { _pAgent = value; } } protected IntPtr pListener = IntPtr.Zero; /// /// 连接事件 /// public TcpAgentEvent.OnConnectEventHandler OnConnect; /// /// 数据发送事件 /// public TcpAgentEvent.OnSendEventHandler OnSend; /// /// 准备连接事件 /// public TcpAgentEvent.OnPrepareConnectEventHandler OnPrepareConnect; /// /// 数据到达事件 /// public TcpAgentEvent.OnReceiveEventHandler OnReceive; /// /// 连接关闭事件 /// public TcpAgentEvent.OnCloseEventHandler OnClose; /// /// 连接出错事件 /// public TcpAgentEvent.OnErrorEventHandler OnError; /// /// 服务关闭事件 /// public TcpAgentEvent.OnShutdownEventHandler OnShutdown; protected bool IsCreate = false; public TcpAgent() { CreateListener(); } ~TcpAgent() { Destroy(); } /// /// 创建socket监听&服务组件 /// /// 是否使用tcpAgent类默认回调函数 /// protected virtual bool CreateListener() { if (IsCreate == true || pListener != IntPtr.Zero || pAgent != IntPtr.Zero) { return false; } pListener = HPSocketSdk.Create_HP_TcpAgentListener(); if (pListener == IntPtr.Zero) { return false; } pAgent = HPSocketSdk.Create_HP_TcpAgent(pListener); if (pAgent == IntPtr.Zero) { return false; } IsCreate = true; return true; } /// /// 释放TcpAgent和TcpAgentListener /// public virtual void Destroy() { Stop(); if (pAgent != IntPtr.Zero) { HPSocketSdk.Destroy_HP_TcpAgent(pAgent); pAgent = IntPtr.Zero; } if (pListener != IntPtr.Zero) { HPSocketSdk.Destroy_HP_TcpAgentListener(pListener); pListener = IntPtr.Zero; } IsCreate = false; } /// /// 启动通讯组件 /// 启动完成后可开始连接远程服务器 /// /// 绑定地址 /// 是否异步 /// public bool Start(string address, bool async = false) { if (string.IsNullOrEmpty(address) == true) { throw new Exception("address is null"); } if (IsStarted == true) { return false; } SetCallback(); return HPSocketSdk.HP_Agent_Start(pAgent, address, async); } /// /// 停止通讯组件 /// /// public bool Stop() { if (IsStarted == false) { return false; } return HPSocketSdk.HP_Agent_Stop(pAgent); } /// /// 连接服务器,连接成功后 IAgentListener 会接收到 OnConnect() 事件 /// /// /// /// /// public bool Connect(string address, ushort port, ref IntPtr connId) { return HPSocketSdk.HP_Agent_Connect(pAgent, address, port, ref connId); } /// /// 发送数据 /// /// /// /// /// public bool Send(IntPtr connId, byte[] bytes, int size) { return HPSocketSdk.HP_Agent_Send(pAgent, connId, bytes, size); } /// /// 发送数据 /// /// /// /// /// public bool Send(IntPtr connId, T obj) { byte[] buffer = StructureToByte(obj); return Send(connId, buffer, buffer.Length); } /// /// 序列化对象后发送数据,序列化对象所属类必须标记[Serializable] /// /// /// /// /// public bool SendBySerializable(IntPtr connId, object obj) { byte[] buffer = ObjectToBytes(obj); return Send(connId, buffer, buffer.Length); } /// /// 发送数据 /// /// /// /// /// public bool Send(IntPtr connId, IntPtr bufferPtr, int size) { return HPSocketSdk.HP_Agent_Send(pAgent, connId, bufferPtr, size); } /// /// 发送数据 /// /// /// /// 针对bytes的偏移 /// 发多大 /// public bool Send(IntPtr connId, byte[] bytes, int offset, int size) { return HPSocketSdk.HP_Agent_SendPart(pAgent, connId, bytes, size, offset); } /// /// 发送数据 /// /// /// /// 针对bufferPtr的偏移 /// 发多大 /// public bool Send(IntPtr connId, IntPtr bufferPtr, int offset, int size) { return HPSocketSdk.HP_Agent_SendPart(pAgent, connId, bufferPtr, size, offset); } /// /// 发送多组数据 /// 向指定连接发送多组数据 /// TCP - 顺序发送所有数据包 /// /// 连接 ID /// 发送缓冲区数组 /// 发送缓冲区数目 /// TRUE.成功,FALSE.失败,可通过 SYSGetLastError() 获取 Windows 错误代码 public bool SendPackets(IntPtr connId, WSABUF[] pBuffers, int count) { return HPSocketSdk.HP_Agent_SendPackets(pAgent, connId, pBuffers, count); } /// /// 发送多组数据 /// 向指定连接发送多组数据 /// TCP - 顺序发送所有数据包 /// /// 连接 ID /// 发送缓冲区数组 /// 发送缓冲区数目 /// TRUE.成功,FALSE.失败,可通过 SYSGetLastError() 获取 Windows 错误代码 public bool SendPackets(IntPtr connId, T[] objects) { bool ret = false; WSABUF[] buffer = new WSABUF[objects.Length]; IntPtr[] ptrs = new IntPtr[buffer.Length]; try { for (int i = 0; i < objects.Length; i++) { buffer[i].Length = Marshal.SizeOf(typeof(T)); ptrs[i] = Marshal.AllocHGlobal(buffer[i].Length); Marshal.StructureToPtr(objects[i], ptrs[i], true); buffer[i].Buffer = ptrs[i]; } ret = SendPackets(connId, buffer, buffer.Length); } catch (Exception ex) { throw ex; } finally { for (int i = 0; i < ptrs.Length; i++) { if (ptrs[i] != IntPtr.Zero) { Marshal.FreeHGlobal(ptrs[i]); } } } return ret; } /// /// 名称:发送小文件 /// 描述:向指定连接发送 4096 KB 以下的小文件 /// /// /// 文件路径 /// 头部附加数据 /// 尾部附加数据 /// TRUE.成功,FALSE.失败,可通过 SYSGetLastError() 获取 Windows 错误代码 public bool SendSmallFile(IntPtr connId, string filePath, ref WSABUF head, ref WSABUF tail) { return HPSocketSdk.HP_TcpAgent_SendSmallFile(pAgent, connId, filePath, ref head, ref tail); } /// /// 名称:发送小文件 /// 描述:向指定连接发送 4096 KB 以下的小文件 /// /// /// 文件路径 /// 头部附加数据,可以为null /// 尾部附加数据,可以为null /// TRUE.成功,FALSE.失败,可通过 SYSGetLastError() 获取 Windows 错误代码 public bool SendSmallFile(IntPtr connId, string filePath, byte[] head, byte[] tail) { IntPtr pHead = IntPtr.Zero; IntPtr pTail = IntPtr.Zero; WSABUF wsaHead = new WSABUF() { Length = 0, Buffer = pHead }; WSABUF wsatail = new WSABUF() { Length = 0, Buffer = pTail }; if (head != null) { wsaHead.Length = head.Length; wsaHead.Buffer = Marshal.UnsafeAddrOfPinnedArrayElement(head, 0); } if (tail != null) { wsaHead.Length = tail.Length; wsaHead.Buffer = Marshal.UnsafeAddrOfPinnedArrayElement(tail, 0); } return SendSmallFile(connId, filePath, ref wsaHead, ref wsatail); } /// /// 名称:发送小文件 /// 描述:向指定连接发送 4096 KB 以下的小文件 /// /// /// 文件路径 /// 头部附加数据,可以为null /// 尾部附加数据,可以为null /// TRUE.成功,FALSE.失败,可通过 SYSGetLastError() 获取 Windows 错误代码 public bool SendSmallFile(IntPtr connId, string filePath, T1 head, T2 tail) { byte[] headBuffer = null; if (head != null) { headBuffer = StructureToByte(head); } byte[] tailBuffer = null; if (tail != null) { StructureToByte(head); } return SendSmallFile(connId, filePath, headBuffer, tailBuffer); } /// /// 断开某个连接 /// /// /// 强制 /// public bool Disconnect(IntPtr connId, bool force = true) { return HPSocketSdk.HP_Agent_Disconnect(pAgent, connId, force); } /// /// 断开超过指定时间的连接 /// /// 毫秒 /// 强制 /// public bool DisconnectLongConnections(uint period, bool force = true) { return HPSocketSdk.HP_Agent_DisconnectLongConnections(pAgent, period, force); } /// /// 断开超过指定时长的静默连接 /// /// 毫秒 /// 强制 /// public bool DisconnectSilenceConnections(uint period, bool force = true) { return HPSocketSdk.HP_Agent_DisconnectSilenceConnections(pAgent, period, force); } /// /// 设置连接的附加数据 /// /// /// /// public bool SetConnectionExtra(IntPtr connId, object obj) { IntPtr ptr = IntPtr.Zero; // 释放附加数据 if (HPSocketSdk.HP_Agent_GetConnectionExtra(pAgent, connId, ref ptr) && ptr != IntPtr.Zero) { Marshal.FreeHGlobal(ptr); ptr = IntPtr.Zero; } if (obj != null) { // 设置附加数据 ptr = Marshal.AllocHGlobal(Marshal.SizeOf(obj)); Marshal.StructureToPtr(obj, ptr, false); } return HPSocketSdk.HP_Agent_SetConnectionExtra(pAgent, connId, ptr); } /// /// 获取附加数据 /// 如设置的是个结构体/类对象,可以用 Type objA = (Type)Marshal.PtrToStructure(ptr, typeof(Type)) 获取 /// 其中Type是结构体/类名,ptr是该方法的传出值,在该方法返回为true的时候可用 /// /// /// /// public bool GetConnectionExtra(IntPtr connId, ref IntPtr ptr) { return HPSocketSdk.HP_Agent_GetConnectionExtra(pAgent, connId, ref ptr) && ptr != IntPtr.Zero; } /// /// 获取错误码 /// public SocketError ErrorCode { get { return HPSocketSdk.HP_Agent_GetLastError(pAgent); } } /// /// 获取错误信息 /// public string ErrorMessage { get { IntPtr ptr = HPSocketSdk.HP_Agent_GetLastErrorDesc(pAgent); string desc = Marshal.PtrToStringUni(ptr); return desc; } } /// /// 获取连接中未发出数据的长度 /// /// /// /// public bool GetPendingDataLength(IntPtr connId, ref int length) { return HPSocketSdk.HP_Agent_GetPendingDataLength(pAgent, connId, ref length); } // 是否启动 public bool IsStarted { get { if (pAgent == IntPtr.Zero) { return false; } return HPSocketSdk.HP_Agent_HasStarted(pAgent); } } /// /// 状态 /// public ServiceState State { get { return HPSocketSdk.HP_Agent_GetState(pAgent); } } public uint ConnectionCount { get { return HPSocketSdk.HP_Agent_GetConnectionCount(pAgent); } } /// /// 获取所有连接,未获取到连接返回null /// /// public IntPtr[] GetAllConnectionIDs() { IntPtr[] arr = null; do { uint count = ConnectionCount; if (count == 0) { break; } arr = new IntPtr[count]; if (HPSocketSdk.HP_Agent_GetAllConnectionIDs(pAgent, arr, ref count)) { if (arr.Length > count) { IntPtr[] newArr = new IntPtr[count]; Array.Copy(arr, newArr, count); arr = newArr; } break; } } while (true); return arr; } /// /// 获取监听socket的地址信息 /// /// /// /// public bool GetLocalAddress(IntPtr connId, ref string ip, ref ushort port) { int ipLength = 40; StringBuilder sb = new StringBuilder(ipLength); bool ret = HPSocketSdk.HP_Agent_GetLocalAddress(pAgent, connId, sb, ref ipLength, ref port); if (ret == true) { ip = sb.ToString(); } return ret; } /// /// 获取该组件对象的连接Id /// /// public bool GetRemoteAddress(IntPtr connId, ref string ip, ref ushort port) { int ipLength = 40; StringBuilder sb = new StringBuilder(ipLength); bool ret = HPSocketSdk.HP_Agent_GetRemoteAddress(pAgent, connId, sb, ref ipLength, ref port); if (ret == true) { ip = sb.ToString(); } return ret; } /// /// 获取指定连接的连接时长(毫秒) /// /// /// /// public bool GetConnectPeriod(IntPtr connId, ref uint period) { return HPSocketSdk.HP_Agent_GetConnectPeriod(pAgent, connId, ref period); } /// /// 获取某个连接静默时间(毫秒) /// /// /// /// public bool GetSilencePeriod(IntPtr connId, ref uint period) { return HPSocketSdk.HP_Agent_GetSilencePeriod(pAgent, connId, ref period); } /////////////////////////////////////////////////////////////////////////////////////// /// /// 获取或设置是否启用地址重用机制(默认:不启用) /// public bool IsReuseAddress { get { return HPSocketSdk.HP_TcpAgent_IsReuseAddress(pAgent); } set { HPSocketSdk.HP_TcpAgent_SetReuseAddress(pAgent, value); } } /// /// 读取或设置工作线程数量(通常设置为 2 * CPU + 2) /// public uint WorkerThreadCount { get { return HPSocketSdk.HP_Agent_GetWorkerThreadCount(pAgent); } set { HPSocketSdk.HP_Agent_SetWorkerThreadCount(pAgent, value); } } /// /// 读取或设置通信数据缓冲区大小(根据平均通信数据包大小调整设置,通常设置为 1024 的倍数) /// public uint SocketBufferSize { get { return HPSocketSdk.HP_TcpAgent_GetSocketBufferSize(pAgent); } set { HPSocketSdk.HP_TcpAgent_SetSocketBufferSize(pAgent, value); } } /// /// 读取或设置 Socket 缓存对象锁定时间(毫秒,在锁定期间该 Socket 缓存对象不能被获取使用) /// public uint FreeSocketObjLockTime { get { return HPSocketSdk.HP_Agent_GetFreeSocketObjLockTime(pAgent); } set { HPSocketSdk.HP_Agent_SetFreeSocketObjLockTime(pAgent, value); } } /// /// 读取或设置 Socket 缓存池大小(通常设置为平均并发连接数量的 1/3 - 1/2) /// public uint FreeSocketObjPool { get { return HPSocketSdk.HP_Agent_GetFreeSocketObjPool(pAgent); } set { HPSocketSdk.HP_Agent_SetFreeSocketObjPool(pAgent, value); } } /// /// 读取或设置内存块缓存池大小(通常设置为 Socket 缓存池大小的 2 - 3 倍) /// public uint FreeBufferObjPool { get { return HPSocketSdk.HP_Agent_GetFreeBufferObjPool(pAgent); } set { HPSocketSdk.HP_Agent_SetFreeBufferObjPool(pAgent, value); } } /// /// 读取或设置 Socket 缓存池回收阀值(通常设置为 Socket 缓存池大小的 3 倍) /// public uint FreeSocketObjHold { get { return HPSocketSdk.HP_Agent_GetFreeSocketObjHold(pAgent); } set { HPSocketSdk.HP_Agent_SetFreeSocketObjHold(pAgent, value); } } /// /// 读取或设置内存块缓存池回收阀值(通常设置为内存块缓存池大小的 3 倍) /// public uint FreeBufferObjHold { get { return HPSocketSdk.HP_Agent_GetFreeBufferObjHold(pAgent); } set { HPSocketSdk.HP_Agent_SetFreeBufferObjHold(pAgent, value); } } /// /// 读取或设置心跳包间隔(毫秒,0 则不发送心跳包)) /// public uint KeepAliveTime { get { return HPSocketSdk.HP_TcpAgent_GetKeepAliveTime(pAgent); } set { HPSocketSdk.HP_TcpAgent_SetKeepAliveTime(pAgent, value); } } /// /// 读取或设置心跳确认包检测间隔(毫秒,0 不发送心跳包,如果超过若干次 [默认:WinXP 5 次, Win7 10 次] 检测不到心跳确认包则认为已断线) /// public uint KeepAliveInterval { get { return HPSocketSdk.HP_TcpAgent_GetKeepAliveInterval(pAgent); } set { HPSocketSdk.HP_TcpAgent_SetKeepAliveInterval(pAgent, value); } } /// /// 读取或设置关闭服务前等待连接关闭的最长时限(毫秒,0 则不等待) /// public uint MaxShutdownWaitTime { get { return HPSocketSdk.HP_Agent_GetMaxShutdownWaitTime(pAgent); } set { HPSocketSdk.HP_Agent_SetMaxShutdownWaitTime(pAgent, value); } } /// /// 读取或设置是否标记静默时间(设置为 TRUE 时 DisconnectSilenceConnections() 和 GetSilencePeriod() 才有效,默认:FALSE) /// public bool IsMarkSilence { get { return HPSocketSdk.HP_Agent_IsMarkSilence(pAgent); } set { HPSocketSdk.HP_Agent_SetMarkSilence(pAgent, value); } } /// /// 读取或设置数据发送策略 /// public SendPolicy SendPolicy { get { return HPSocketSdk.HP_Agent_GetSendPolicy(pAgent); } set { HPSocketSdk.HP_Agent_SetSendPolicy(pAgent, value); } } /// /// 读取或设置数据接收策略 /// public RecvPolicy RecvPolicy { get { return HPSocketSdk.HP_Agent_GetRecvPolicy(pAgent); } set { HPSocketSdk.HP_Agent_SetRecvPolicy(pAgent, value); } } /// /// 根据错误码返回错误信息 /// /// /// public string GetSocketErrorDesc(SocketError code) { IntPtr ptr = HPSocketSdk.HP_GetSocketErrorDesc(code); string desc = Marshal.PtrToStringUni(ptr); return desc; } /////////////////////////////////////////////////////////////////////////////////////// HPSocketCS.SDK.HPSocketSdk.OnPrepareConnect _OnPrepareConnect = null; HPSocketCS.SDK.HPSocketSdk.OnConnect _OnConnect = null; HPSocketCS.SDK.HPSocketSdk.OnReceive _OnReceive = null; HPSocketCS.SDK.HPSocketSdk.OnSend _OnSend = null; HPSocketCS.SDK.HPSocketSdk.OnClose _OnClose = null; HPSocketCS.SDK.HPSocketSdk.OnError _OnError = null; HPSocketCS.SDK.HPSocketSdk.OnShutdown _OnShutdown = null; /// /// 设置回调函数 /// protected virtual void SetCallback() { _OnPrepareConnect = new HPSocketSdk.OnPrepareConnect(SDK_OnPrepareConnect); _OnConnect = new HPSocketSdk.OnConnect(SDK_OnConnect); _OnSend = new HPSocketSdk.OnSend(SDK_OnSend); _OnReceive = new HPSocketSdk.OnReceive(SDK_OnReceive); _OnClose = new HPSocketSdk.OnClose(SDK_OnClose); _OnError = new HPSocketSdk.OnError(SDK_OnError); _OnShutdown = new HPSocketSdk.OnShutdown(SDK_OnShutdown); // 设置 Socket 监听器回调函数 HPSocketSdk.HP_Set_FN_Agent_OnPrepareConnect(pListener, _OnPrepareConnect); HPSocketSdk.HP_Set_FN_Agent_OnConnect(pListener, _OnConnect); HPSocketSdk.HP_Set_FN_Server_OnSend(pListener, _OnSend); HPSocketSdk.HP_Set_FN_Server_OnReceive(pListener, _OnReceive); HPSocketSdk.HP_Set_FN_Server_OnError(pListener, _OnError); HPSocketSdk.HP_Set_FN_Server_OnClose(pListener, _OnClose); HPSocketSdk.HP_Set_FN_Agent_OnShutdown(pListener, _OnShutdown); } protected virtual HandleResult SDK_OnPrepareConnect(IntPtr connId, uint socket) { if (OnPrepareConnect != null) { OnPrepareConnect(connId, socket); } return HandleResult.Ignore; } protected virtual HandleResult SDK_OnConnect(IntPtr connId) { if (OnConnect != null) { OnConnect(connId); } return HandleResult.Ignore; } protected virtual HandleResult SDK_OnSend(IntPtr connId, IntPtr pData, int length) { if (OnSend != null) { OnSend(connId, pData, length); } return HandleResult.Ignore; } protected virtual HandleResult SDK_OnReceive(IntPtr connId, IntPtr pData, int length) { if (OnReceive != null) { OnReceive(connId, pData, length); } return HandleResult.Ignore; } protected virtual HandleResult SDK_OnClose(IntPtr connId) { if (OnClose != null) { OnClose(connId); } return HandleResult.Ignore; } protected virtual HandleResult SDK_OnError(IntPtr connId, SocketOperation enOperation, int errorCode) { if (OnError != null) { OnError(connId, enOperation, errorCode); } return HandleResult.Ignore; } protected virtual HandleResult SDK_OnShutdown() { if (OnShutdown != null) { OnShutdown(); } return HandleResult.Ignore; } ///////////////////////////////////////////////////////////////////////// /// /// 获取系统返回的错误码 /// /// public int SYSGetLastError() { return HPSocketSdk.SYS_GetLastError(); } /// /// 调用系统的 ::WSAGetLastError() 方法获取通信错误代码 /// /// public int SYSWSAGetLastError() { return HPSocketSdk.SYS_WSAGetLastError(); } /// /// 调用系统的 setsockopt() /// /// /// /// /// /// /// /// public int SYS_SetSocketOption(IntPtr sock, int level, int name, IntPtr val, int len) { return HPSocketSdk.SYS_SetSocketOption(sock, level, name, val, len); } /// /// 调用系统的 getsockopt() /// /// /// /// /// /// /// /// public int SYSGetSocketOption(IntPtr sock, int level, int name, IntPtr val, ref int len) { return HPSocketSdk.SYS_GetSocketOption(sock, level, name, val, ref len); } /// /// 调用系统的 ioctlsocket() /// /// /// /// /// /// public int SYSIoctlSocket(IntPtr sock, long cmd, IntPtr arg) { return HPSocketSdk.SYS_IoctlSocket(sock, cmd, arg); } /// /// 调用系统的 ::WSAIoctl() /// /// /// /// /// /// /// /// /// public int SYS_WSAIoctl(IntPtr sock, uint dwIoControlCode, IntPtr lpvInBuffer, uint cbInBuffer, IntPtr lpvOutBuffer, uint cbOutBuffer, uint lpcbBytesReturned) { return HPSocketSdk.SYS_WSAIoctl(sock, dwIoControlCode, lpvInBuffer, cbInBuffer, lpvOutBuffer, cbOutBuffer, lpcbBytesReturned); } /// /// 由结构体转换为byte数组 /// public byte[] StructureToByte(T structure) { int size = Marshal.SizeOf(typeof(T)); byte[] buffer = new byte[size]; IntPtr bufferIntPtr = Marshal.AllocHGlobal(size); try { Marshal.StructureToPtr(structure, bufferIntPtr, true); Marshal.Copy(bufferIntPtr, buffer, 0, size); } finally { Marshal.FreeHGlobal(bufferIntPtr); } return buffer; } /// /// 由byte数组转换为结构体 /// public T ByteToStructure(byte[] dataBuffer) { object structure = null; int size = Marshal.SizeOf(typeof(T)); IntPtr allocIntPtr = Marshal.AllocHGlobal(size); try { Marshal.Copy(dataBuffer, 0, allocIntPtr, size); structure = Marshal.PtrToStructure(allocIntPtr, typeof(T)); } finally { Marshal.FreeHGlobal(allocIntPtr); } return (T)structure; } /// /// 对象序列化成byte[] /// /// /// public byte[] ObjectToBytes(object obj) { using (MemoryStream ms = new MemoryStream()) { IFormatter formatter = new BinaryFormatter(); formatter.Serialize(ms, obj); return ms.GetBuffer(); } } /// /// byte[]序列化成对象 /// /// /// public object BytesToObject(byte[] bytes) { using (MemoryStream ms = new MemoryStream(bytes)) { IFormatter formatter = new BinaryFormatter(); return formatter.Deserialize(ms); } } } }