/// <summary> /// 创建一个新的 PackageEventArgs 对象. /// </summary> public PackageEventArgs(bool isMultiPackage, Entity.PackedNetworkMessage package, Entity.PackedNetworkMessage[] packages) { this.IsMultiPackage = isMultiPackage; this.Package = package; this.Packages = packages; this.IsHandled = false; }
/// <summary> /// 将已经打包的消息发送出去 /// </summary> /// <param name="packedMessage">已经打包的消息</param> /// <param name="confirmReceived">是否回发确认消息</param> public void Send(Entity.PackedNetworkMessage packedMessage) { if (IsInitialized) { client.Send(packedMessage.Data, packedMessage.Data.Length, packedMessage.RemoteIP); if (packedMessage.IsReceiveSignalRequired) { PushSendItemToList(packedMessage); } } }
/// <summary> /// 发送打包好的消息 /// </summary> /// <param name="cm"></param> /// <returns>返回发出的消息包编号</returns> public ulong Send(Message cm) { if (!Client.IsInitialized) { return(0ul); } cm.Options |= (ulong)Define.Consts.Cmd_All_Option.EnableNewDataContract; MessageEventArgs mea = new MessageEventArgs(cm) { Message = cm, IsHandled = false, Host = cm.Host }; OnMessageSending(mea); if (mea.IsHandled) { return(mea.Message.PackageNo); } //判断远程主机是否支持这个模式 if (!Config.ForceOldContract && cm.Host != null && cm.Host.IsEnhancedContractEnabled) { Entity.PackedNetworkMessage[] pnm = MessagePackerV2.BuildNetworkMessage(cm); PackageEventArgs pea = new PackageEventArgs(pnm.Length > 1, pnm[0], pnm); OnPckageSending(pea); if (!pea.IsHandled) { Array.ForEach(pnm, s => { Client.Send(s); }); OnPackageSended(pea); } } else { Entity.PackedNetworkMessage pn = MessagePacker.BuildNetworkMessage(cm); PackageEventArgs pe = new PackageEventArgs(false, pn, null); OnPckageSending(pe); if (!pe.IsHandled) { Client.Send(pn); OnPackageSended(pe); } } OnMessageSended(mea); return(cm.PackageNo); }
/// <summary> /// 尝试将收到的网络包解析为实体 /// </summary> /// <param name="pack">收到的网络包</param> /// <returns></returns> /// <remarks>如果收到的包是分片包,且其所有子包尚未接受完全,则会返回空值</remarks> public static IPMessager.Entity.Message TryToTranslateMessage(Entity.PackedNetworkMessage pack) { if (pack == null || pack.PackageIndex >= pack.PackageCount - 1) { return(null); } else if (pack.PackageCount == 1) { return(ParseToMessage(pack)); } else { if (packageCache.ContainsKey(pack.PackageNo)) { Entity.PackedNetworkMessage[] array = packageCache[pack.PackageNo]; array[pack.PackageIndex] = pack; //检测是否完整 if (Array.FindIndex(array, s => s == null) == -1) { packageCache.Remove(pack.PackageNo); return(ParseToMessage(array)); } else { return(null); } } else { Entity.PackedNetworkMessage[] array = new Entity.PackedNetworkMessage[pack.PackageCount]; array[pack.PackageIndex] = pack; packageCache.Add(pack.PackageNo, array); return(null); } } }
/// <summary> /// 尝试将收到的网络包解析为实体 /// </summary> /// <param name="pack">收到的网络包</param> /// <returns></returns> /// <remarks>如果收到的包是分片包,且其所有子包尚未接受完全,则会返回空值</remarks> public static IPMessager.Entity.Message TryToTranslateMessage(Entity.PackedNetworkMessage pack) { if (pack == null || pack.PackageIndex >= pack.PackageCount - 1) { return(null); } if (pack.PackageCount == 1) { return(ParseToMessage(pack)); } lock (packageCache) { if (packageCache.ContainsKey(pack.PackageNo)) { var array = packageCache[pack.PackageNo]; array[pack.PackageIndex] = pack; //检测是否完整 //TODO 这里没有过期机制.当丢失数据包永远收不到的时候,会发生数据包永远保存在内存中的泄露 //TODO 要解决此问题,需要启动定时器定时检查数据包队列,并丢弃过期数据 if (Array.FindIndex(array, s => s == null) == -1) { packageCache.Remove(pack.PackageNo); return(ParseToMessage(array)); } return(null); } else { var array = new Entity.PackedNetworkMessage[pack.PackageCount]; array[pack.PackageIndex] = pack; packageCache.Add(pack.PackageNo, array); return(null); } } }
/// <summary> /// 检测是否需要发送回复包来确认收到 /// </summary> /// <param name="message"></param> /// <returns></returns> static bool DetermineConfirm(Entity.PackedNetworkMessage message) { return(message.IsReceiveSignalRequired); }
/// <summary> /// 获得消息包的字节流 /// </summary> /// <param name="remoteIp">远程主机地址</param> /// <param name="packageNo">包编号</param> /// <param name="command">命令</param> /// <param name="options">参数</param> /// <param name="userName">用户名</param> /// <param name="hostName">主机名</param> /// <param name="content">正文消息</param> /// <param name="extendContents">扩展消息</param> /// <returns></returns> public static Entity.PackedNetworkMessage[] BuildNetworkMessage(IPEndPoint remoteIp, ulong packageNo, Define.Consts.Commands command, ulong options, string userName, string hostName, byte[] content, byte[] extendContents) { options |= (ulong)Define.Consts.Cmd_Send_Option.Content_Unicode; //每次发送所能容下的数据量 var maxBytesPerPackage = Define.Consts.MAX_UDP_PACKAGE_LENGTH - PackageHeaderLength; //压缩数据流 var ms = new System.IO.MemoryStream(); var zip = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Compress); var bw = new System.IO.BinaryWriter(zip, System.Text.Encoding.Unicode); //写入头部数据 bw.Write(packageNo); //包编号 bw.Write(((ulong)command) | options); //命令|选项 bw.Write(userName); //用户名 bw.Write(hostName); //主机名 bw.Write(content == null ? 0 : content.Length); //数据长度 //写入消息数据 if (content != null) bw.Write(content); bw.Write(extendContents == null ? 0 : extendContents.Length); //补充数据长度 if (extendContents != null) bw.Write(extendContents); bw.Close(); zip.Close(); ms.Flush(); ms.Seek(0, System.IO.SeekOrigin.Begin); //打包数据总量 var dataLength = (int)ms.Length; var packageCount = (int)Math.Ceiling(dataLength * 1.0 / maxBytesPerPackage); var pnma = new PackedNetworkMessage[packageCount]; for (var i = 0; i < packageCount; i++) { var count = i == packageCount - 1 ? dataLength - maxBytesPerPackage * (packageCount - 1) : maxBytesPerPackage; var buf = new byte[count + PackageHeaderLength]; buf[0] = VersionHeader; BitConverter.GetBytes(packageNo).CopyTo(buf, 1); BitConverter.GetBytes(dataLength).CopyTo(buf, 9); BitConverter.GetBytes(packageCount).CopyTo(buf, 13); BitConverter.GetBytes(i).CopyTo(buf, 17); buf[21] = Define.Consts.Check(options, Define.Consts.Cmd_All_Option.RequireReceiveCheck) ? (byte)1 : (byte)0; //包确认标志? ms.Read(buf, 32, buf.Length - 32); pnma[i] = new Entity.PackedNetworkMessage() { Data = buf, PackageCount = packageCount, PackageIndex = i, PackageNo = packageNo, RemoteIP = remoteIp, SendTimes = 0, Version = 2, IsReceiveSignalRequired = buf[21] == 1 }; } ms.Close(); return pnma; }
/// <summary> /// 尝试将收到的网络包解析为实体 /// </summary> /// <param name="pack">收到的网络包</param> /// <returns></returns> /// <remarks>如果收到的包是分片包,且其所有子包尚未接受完全,则会返回空值</remarks> public static IPMessager.Entity.Message TryToTranslateMessage(Entity.PackedNetworkMessage pack) { if (pack == null || pack.PackageIndex >= pack.PackageCount - 1) return null; if (pack.PackageCount == 1) return ParseToMessage(pack); lock (packageCache) { if (packageCache.ContainsKey(pack.PackageNo)) { var array = packageCache[pack.PackageNo]; array[pack.PackageIndex] = pack; //检测是否完整 //TODO 这里没有过期机制.当丢失数据包永远收不到的时候,会发生数据包永远保存在内存中的泄露 //TODO 要解决此问题,需要启动定时器定时检查数据包队列,并丢弃过期数据 if (Array.FindIndex(array, s => s == null) == -1) { packageCache.Remove(pack.PackageNo); return ParseToMessage(array); } return null; } else { var array = new Entity.PackedNetworkMessage[pack.PackageCount]; array[pack.PackageIndex] = pack; packageCache.Add(pack.PackageNo, array); return null; } } }
/// <summary> /// 获得消息包的字节流 /// </summary> /// <param name="remoteIp">远程主机地址</param> /// <param name="packageNo">包编号</param> /// <param name="command">命令</param> /// <param name="options">参数</param> /// <param name="userName">用户名</param> /// <param name="hostName">主机名</param> /// <param name="content">正文消息</param> /// <param name="extendContents">扩展消息</param> /// <returns></returns> public static Entity.PackedNetworkMessage[] BuildNetworkMessage(IPEndPoint remoteIp, ulong packageNo, Define.Consts.Commands command, ulong options, string userName, string hostName, byte[] content, byte[] extendContents) { options |= (ulong)Define.Consts.Cmd_Send_Option.Content_Unicode; //每次发送所能容下的数据量 int maxBytesPerPackage = Define.Consts.MAX_UDP_PACKAGE_LENGTH - PackageHeaderLength; //压缩数据流 System.IO.MemoryStream ms = new System.IO.MemoryStream(); System.IO.Compression.GZipStream zip = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Compress); System.IO.BinaryWriter bw = new System.IO.BinaryWriter(zip, System.Text.Encoding.Unicode); //写入头部数据 bw.Write(packageNo); //包编号 bw.Write(((ulong)command) | options); //命令|选项 bw.Write(userName); //用户名 bw.Write(hostName); //主机名 bw.Write(content == null ? 0 : content.Length); //数据长度 //写入消息数据 if (content != null) { bw.Write(content); } bw.Write(extendContents == null ? 0 : extendContents.Length); //补充数据长度 if (extendContents != null) { bw.Write(extendContents); } bw.Close(); zip.Close(); ms.Flush(); ms.Seek(0, System.IO.SeekOrigin.Begin); //打包数据总量 int dataLength = (int)ms.Length; int packageCount = (int)Math.Ceiling(dataLength * 1.0 / maxBytesPerPackage); Entity.PackedNetworkMessage[] pnma = new PackedNetworkMessage[packageCount]; for (int i = 0; i < packageCount; i++) { int count = i == packageCount - 1 ? dataLength - maxBytesPerPackage * (packageCount - 1) : maxBytesPerPackage; byte[] buf = new byte[count + PackageHeaderLength]; buf[0] = VersionHeader; BitConverter.GetBytes(packageNo).CopyTo(buf, 1); BitConverter.GetBytes(dataLength).CopyTo(buf, 9); BitConverter.GetBytes(packageCount).CopyTo(buf, 13); BitConverter.GetBytes(i).CopyTo(buf, 17); buf[21] = Define.Consts.Check(options, Define.Consts.Cmd_All_Option.RequireReceiveCheck) ? (byte)1 : (byte)0; //包确认标志? ms.Read(buf, 32, buf.Length - 32); pnma[i] = new Entity.PackedNetworkMessage() { Data = buf, PackageCount = packageCount, PackageIndex = i, PackageNo = packageNo, RemoteIP = remoteIp, SendTimes = 0, Version = 2, IsReceiveSignalRequired = buf[21] == 1 }; } ms.Close(); return(pnma); }