C# Socket IPackets
using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; using System.Text; using System.IO; namespace Rocky.Net { [ContractClass(typeof(IPacketsContract))] public interface IPackets { long ContentLength { get; } int? BufferSize { get; set; } bool Buffer { get; set; } Stream InputStream { get; } } [ContractClassFor(typeof(IPackets))] internal abstract class IPacketsContract : IPackets { long IPackets.ContentLength { get { Contract.Ensures(Contract.Result<long>() >= SocketHelper.Special); return default(long); } } int? IPackets.BufferSize { get { return default(int?); } set { } } bool IPackets.Buffer { get { return default(bool); } set { } } Stream IPackets.InputStream { get { Contract.Ensures(Contract.Result<Stream>() != null); return default(Stream); } } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace Rocky.Net { public interface IPacketsFactory { IPackets Create(object graph); IPackets Create(Stream inputStream, long contentLength); } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics.Contracts; using System.IO; namespace Rocky.Net { internal class Packets : IPackets { #region Fields private Stream _stream; #endregion #region Properties public long ContentLength { get; private set; } public int? BufferSize { get; set; } public bool Buffer { get; set; } public Stream InputStream { get { return _stream; } } #endregion #region Constructors public Packets(byte[] binary) : this(new MemoryStream(binary, 0, binary.Length, true, false), binary.Length) { } public Packets(Stream inputStream, long contentLength) { Contract.Requires(inputStream != null); _stream = inputStream; this.ContentLength = contentLength; } #endregion } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace Rocky.Net { internal sealed class PacketsFactory : IPacketsFactory { public IPackets Create(object graph) { byte[] binary = Serializer.Serialize(graph); return new Packets(binary); } public IPackets Create(Stream inputStream, long contentLength) { return new Packets(inputStream, contentLength); } } }
#region Packets /// <summary> /// 同步发送数据包 /// </summary> /// <param name="instance"></param> /// <param name="pack">数据包</param> /// <param name="progress">进度器</param> /// <returns> /// -1 远程连接关闭 /// >=0 已发送的字节数 /// </returns> public static long SendPackets(this Socket instance, IPackets pack, bool acceptLength = true, TransferProgress progress = null) { Contract.Requires(instance != null); Contract.Requires(pack != null); var netStream = new NetworkStream(instance, FileAccess.Write, false); Stream src = netStream, dest = pack.InputStream; if (pack.Buffer) { src = new BufferedStream(netStream, pack.BufferSize.GetValueOrDefault(4096)); } long totalTransferred = 0L, contentLength = pack.ContentLength; if (contentLength == SocketHelper.Special) { try { contentLength = pack.InputStream.Length; } catch (NotSupportedException) { } } ArraySegment<byte> seg; BufferSegment.MemoryBuffer.Take(out seg); bool doProg = false, unknownLength = contentLength == SocketHelper.Special; try { if (acceptLength) { instance.Send(BitConverter.GetBytes(contentLength)); } if (progress != null) { doProg = true; progress.Start(contentLength); } int read; while ((unknownLength || totalTransferred < contentLength) && (read = dest.Read(seg)) != 0) { src.Write(seg, read); src.Flush(); totalTransferred += read; if (doProg) { progress.OnProgressChanged(read, totalTransferred); } #if Sleep Thread.Sleep(10); #endif } if (!unknownLength && totalTransferred != contentLength) { throw new InvalidOperationException("输入流长度和数据包长度必须相同"); } } catch (IOException ex) { var sockEx = ex.InnerException as SocketException; if (sockEx != null && sockEx.ErrorCode == 10054) { return SocketHelper.Special; } throw; } finally { if (doProg) { progress.Stop(); } BufferSegment.MemoryBuffer.Return(ref seg); src.Dispose(); } return totalTransferred; } /// <summary> /// 同步接收数据包 /// </summary> /// <param name="instance"></param> /// <param name="pack">数据包</param> /// <param name="progress">进度器</param> /// <returns> /// -1 远程连接关闭 /// >=0 已接受的字节数 /// </returns> public static long ReceivePackets(this Socket instance, IPackets pack, bool acceptLength = true, TransferProgress progress = null) { Contract.Requires(instance != null); Contract.Requires(pack != null); var netStream = new NetworkStream(instance, FileAccess.Read, false); Stream src = netStream, dest = pack.InputStream; if (pack.Buffer) { src = new BufferedStream(netStream, pack.BufferSize.GetValueOrDefault(4096)); } long totalTransferred = 0L, contentLength = pack.ContentLength; ArraySegment<byte> seg; BufferSegment.MemoryBuffer.Take(out seg); bool doProg = false, unknownLength = contentLength == SocketHelper.Special; try { if (acceptLength) { byte[] buffer = new byte[SocketHelper.PerLongSize]; instance.Receive(buffer); contentLength = buffer.ToInt64(0); } if (progress != null) { doProg = true; progress.Start(contentLength); } int read; while ((unknownLength || totalTransferred < contentLength) && (read = src.Read(seg)) != 0) { dest.Write(seg, read); dest.Flush(); totalTransferred += read; if (doProg) { progress.OnProgressChanged(read, totalTransferred); } #if Sleep Thread.Sleep(10); #endif } // recv == 0, 远程主动关闭连接 if (totalTransferred < contentLength) { return SocketHelper.Special; } } catch (IOException ex) { var sockEx = ex.InnerException as SocketException; // 远程强制关闭连接 if (sockEx != null && sockEx.ErrorCode == 10054) { return SocketHelper.Special; } throw; } finally { if (doProg) { progress.Stop(); } BufferSegment.MemoryBuffer.Return(ref seg); src.Dispose(); } return totalTransferred; } #endregion
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using System.Diagnostics.Contracts; using System.IO; namespace Rocky.Net { public class SocketSyncArgs : EventArgs { #region Fields private IPacketsFactory _packFac; private IPackets _header, _content; #endregion #region Properties public bool Buffer { get; set; } public bool TransferHeader { get; set; } public object HeaderEntity { get; set; } public TransferProgress Progress { get; set; } public bool IsShutdown { get; internal set; } #endregion #region Constructors public SocketSyncArgs() { _packFac = SocketHelper.CreatePacketsFactory(); } #endregion #region Methods [DebuggerStepThrough] internal IPackets[] GetPackets() { if (_content == null) { throw new InvalidOperationException("未设置内容包"); } if (this.HeaderEntity != null) { _header = _packFac.Create(this.HeaderEntity); } return new IPackets[] { _header, _content }; } public void SetPackets(Stream inputStream, long contentLength) { Contract.Requires(inputStream != null); _content = _packFac.Create(inputStream, contentLength); this.IsShutdown = false; } #endregion } }
/// <summary> /// 同步发送SocketSyncArgs /// </summary> /// <param name="sock"></param> /// <param name="e"></param> /// <returns>已发送字节数(不包含HeaderPackets)</returns> public static long SendSync(this Socket sock, SocketSyncArgs e, bool acceptLength = true) { var packs = e.GetPackets(); long sent; if (e.TransferHeader) { if (packs[0] == null) { throw new InvalidOperationException("头对象为空"); } sent = sock.SendPackets(packs[0]); if (sent == SocketHelper.Special) { e.IsShutdown = true; goto done; } } packs[1].Buffer = e.Buffer; sent = sock.SendPackets(packs[1], acceptLength, e.Progress); if (sent == SocketHelper.Special) { e.IsShutdown = true; } done: return sent; } /// <summary> /// 同步接收SocketSyncArgs /// </summary> /// <param name="sock"></param> /// <param name="e"></param> /// <param name="transferLength"></param> /// <returns>已接收字节数(不包含HeaderPackets)</returns> public static long ReceiveSync(this Socket sock, SocketSyncArgs e, bool acceptLength = true) { var packs = e.GetPackets(); long recv; if (e.TransferHeader) { if (packs[0] == null) { throw new InvalidOperationException("头对象为空"); } recv = sock.ReceivePackets(packs[0]); if (recv == SocketHelper.Special) { e.IsShutdown = true; goto done; } } packs[1].Buffer = e.Buffer; recv = sock.ReceivePackets(packs[1], acceptLength, e.Progress); if (recv == SocketHelper.Special) { e.IsShutdown = true; } done: return recv; }