/// <summary> /// 通过广播发送消息 /// </summary> /// <param name="cmd">命令</param> /// <param name="options">参数</param> /// <param name="normalMsg">常规信息</param> /// <param name="extendMessage">扩展消息</param> /// <param name="sendCheck">是否检查发送到</param> /// <returns>返回发出的消息包编号</returns> public void Send(Define.Consts.Commands cmd, ulong options, string normalMsg, string extendMessage) { if (!Client.IsInitialized) { return; } SendWithNoCheck(null, cmd, options, normalMsg, extendMessage); }
/// <summary> /// 发送消息并且要求对方返回已接收消息 /// </summary> /// <param name="host">远程主机.如果为null则会抛出异常</param> /// <param name="cmd">命令</param> /// <param name="options">参数</param> /// <param name="normalMsg">常规信息</param> /// <param name="extendMessage">扩展消息</param> /// <param name="sendCheck">是否检查发送到</param> /// <returns>返回发出的消息包编号</returns> public ulong SendWithCheck(Host host, Define.Consts.Commands cmd, ulong options, byte[] normalMsg, byte[] extendMessage) { if (host == null) { throw new ArgumentNullException("host"); } return(Send(host, host.HostSub.Ipv4Address, cmd, options, normalMsg, extendMessage, true)); }
/// <summary> /// 发送消息 /// </summary> /// <param name="remoteEndPoint">远程主机地址</param> /// <param name="cmd">命令</param> /// <param name="options">参数</param> /// <param name="normalMsg">常规信息</param> /// <param name="extendMessage">扩展消息</param> /// <param name="sendCheck">是否检查发送到</param> /// <returns>返回发出的消息包编号</returns> public ulong Send(Host host, IPEndPoint remoteEndPoint, Define.Consts.Commands cmd, ulong options, string normalMsg, string extendMessage, bool sendCheck) { Message cm = Message.Create(host, remoteEndPoint, Config.GetRandomTick(), Config.HostName, Config.HostUserName, cmd, options, normalMsg, extendMessage); if (sendCheck) { cm.IsRequireReceiveCheck = sendCheck; } return(Send(cm)); }
/// <summary> /// 以二进制模式发送消息 /// </summary> /// <param name="host">关联的远程主机,不可以为null</param> /// <param name="remoteEndPoint">远程主机地址</param> /// <param name="cmd">命令</param> /// <param name="options">参数</param> /// <param name="normalMsg">常规信息</param> /// <param name="extendMessage">扩展消息</param> /// <param name="sendCheck">是否检查发送到</param> /// <exception cref="InvalidOperationException">如果对方主机不在列表中,或未知是否支持增强协议,则会抛出此异常</exception> /// <returns>返回发出的消息包编号</returns> public ulong Send(Host host, IPEndPoint remoteEndPoint, Define.Consts.Commands cmd, ulong options, byte[] normalMsg, byte[] extendMessage, bool sendCheck) { if (!Client.IsInitialized) { return(0ul); } //判断远程主机是否支持这个模式 if (host == null || !host.IsEnhancedContractEnabled) { throw new InvalidOperationException("尚不知道主机是否支持增强协议模式,无法以二进制模式发送消息!"); } Message cm = Message.Create(host, remoteEndPoint, Config.GetRandomTick(), Config.HostName, Config.NickName, cmd, options, "", ""); cm.ExtendMessageBytes = extendMessage; cm.NormalMsgBytes = normalMsg; cm.IsRequireReceiveCheck = sendCheck; //设置选项 if (sendCheck) { cm.Options |= (ulong)Define.Consts.Cmd_All_Option.RequireReceiveCheck; } cm.Options |= (ulong)Define.Consts.Cmd_All_Option.EnableNewDataContract | (ulong)Define.Consts.Cmd_All_Option.BinaryMessage; MessageEventArgs mea = new MessageEventArgs(cm) { Message = cm, IsHandled = false, Host = host }; OnMessageSending(mea); if (mea.IsHandled) { return(mea.Message.PackageNo); } 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); } OnMessageSended(mea); return(cm.PackageNo); }
/// <summary> /// 直接向目标IP发送信息 /// </summary> /// <param name="host">远程主机</param> /// <param name="cmd">命令</param> /// <param name="options">参数</param> /// <param name="normalMsg">常规信息</param> /// <param name="extendMessage">扩展消息</param> /// <param name="sendCheck">是否检查发送到</param> /// <returns>返回发出的消息包编号</returns> public ulong SendByIp(IPEndPoint remoteEndPoint, Define.Consts.Commands cmd, ulong options, string normalMsg, string extendMessage) { return(Send(null, remoteEndPoint ?? broadcastEndPoint, cmd, options, normalMsg, extendMessage, false)); }
/// <summary> /// 发送消息 /// </summary> /// <param name="host">远程主机</param> /// <param name="cmd">命令</param> /// <param name="options">参数</param> /// <param name="normalMsg">常规信息</param> /// <param name="extendMessage">扩展消息</param> /// <param name="sendCheck">是否检查发送到</param> /// <returns>返回发出的消息包编号</returns> public ulong SendWithNoCheck(Host host, Define.Consts.Commands cmd, ulong options, string normalMsg, string extendMessage) { return(Send(host, host == null ? broadcastEndPoint : host.HostSub.Ipv4Address, cmd, options, normalMsg, extendMessage, false)); }
/// <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); }
/// <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) { using (System.IO.MemoryStream bufferStream = new System.IO.MemoryStream()) { int maxLength = Consts.MAX_UDP_PACKAGE_LENGTH; byte[] buffer; /* * 注意: * 1.优先保证扩展信息,如果不能保证则返回失败 * 2.保证扩展消息的前提下,文本消息可以截取 * */ //写入消息头 ulong cmdInfo = (ulong)command | options; buffer = System.Text.Encoding.Default.GetBytes(string.Format("{0}:{1}:{2}:{3}:{4}:", (char)Consts.VersionNumber, packageNo, userName, hostName, cmdInfo)); bufferStream.Write(buffer, 0, buffer.Length); //计算扩展消息 int extendMessageLength = extendContents == null ? 0 : extendContents.Length; if (extendMessageLength + bufferStream.Length > maxLength) { extendContents = null; } extendMessageLength = extendContents == null ? 0 : extendContents.Length + 1; //写入文本消息 if (content != null) { if (content.Length <= maxLength - extendMessageLength - bufferStream.Length) { bufferStream.Write(content, 0, content.Length); } else { bufferStream.Write(content, 0, maxLength - extendMessageLength - (int)bufferStream.Length); } } //写入扩展消息? if (extendMessageLength > 0) { bufferStream.WriteByte(0); bufferStream.Write(extendContents, 0, extendMessageLength - 1); } bufferStream.Seek(0, System.IO.SeekOrigin.Begin); buffer = bufferStream.ToArray(); return(new Entity.PackedNetworkMessage() { PackageCount = 1, PackageIndex = 0, Data = buffer, SendTimes = 0, PackageNo = packageNo, RemoteIP = remoteIp, //回避BUG:全局参数里面,Absence 选项和 SendCheck 是一样的 IsReceiveSignalRequired = command != Consts.Commands.Br_Absence && Define.Consts.Check(options, Consts.Cmd_Send_Option.SendCheck) && remoteIp.Address != IPAddress.Broadcast, Version = 0 }); } }