using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text; using Common; using Dao; using Domain; using RCUHost.Protocols; namespace RCUHost.Implement { public class UpdateConfigReceiver : GenericReceiverBase, IUpdateConfigReceiver { private static log4net.ILog logger = log4net.LogManager.GetLogger(typeof(UpdateConfigReceiver)); private const int BLOCK_SIZE = 512; //TFTP块大小512字节 public void Update(HostUpdate hostUpdate, IList hosts) { if (hosts == null || hosts.Count == 0) { throw new ApplicationException("升级失败,没有找到需要升级的主机。"); } if (String.IsNullOrEmpty(hostUpdate.Href)) { throw new ApplicationException("升级失败,无效的配置文件。"); } string updateFile = Tools.GetApplicationPath() + hostUpdate.Href; if (!File.Exists(updateFile)) { throw new ApplicationException("升级失败,【" + updateFile + "】不是有效的配置文件。"); } FileInfo fileInfo = new FileInfo(updateFile); ushort blockNum = (ushort)Math.Ceiling((double)fileInfo.Length / BLOCK_SIZE); //升级配置文件 foreach (var host in hosts) { SendUpdateRequest(host, hostUpdate.Md5, blockNum); //this.updateHostList.Add(new UpdateHostWorker(host, hostUpdate)); } } public override void Process(ReceiverContext context) { //base.Process(context); //int startIndex = StructConverter.SizeOf(context.SystemHeader); //UpdateConfigPacketReply? reply = DecodeUpdateConfigPacketReply(context.Data, startIndex); //if (reply.HasValue) //{ // logger.Error(string.Format("收到配置文件升级回复命令({0}:{1}):{2}", context.RemoteEndPoint.Address.ToString(), context.RemoteEndPoint.Port, Tools.ByteToString(context.Data))); // var updateHostWorker = updateHostList.FirstOrDefault(r => r.Host.HostNumber == context.SystemHeader.Value.HostNumber.ToString()); // if (updateHostWorker != null) // { // //主机升级后重启会发送回复搜索命令,这时更新版本号 // if (reply.Value.Status == UpdateHostPacketReply.Ready) // { // updateHostWorker.Update(); // } // else // { // updateHostList.Remove(updateHostWorker); // } // } //} } public override CommandType CommandType { get { return CommandType.UpdateConfig; } } #region Private Methods /// /// 发送升级指令到RCU主机 /// /// /// 升级文件MD5值 public void SendUpdateRequest(Host host, string updateFileMd5, ushort blockNum) { byte[] data = CreateUpdateConfigRequestPacket(updateFileMd5, blockNum); Send(data, host.HostNumber, host.MAC);// host.IP, host.Port); } /// /// 创建升级配置数据请求数据包 /// /// 升级文件MD5值 /// 块数量 /// private byte[] CreateUpdateConfigRequestPacket(string updateFileMd5, ushort blockNum) { SystemHeader systemHeader = CreateSystemHeader(); int headerSize = StructConverter.SizeOf(systemHeader); #if DEBUG byte[] ipArr = IPAddress.Parse(Tools.GetLocalIP()).GetAddressBytes(); #else byte[] ipArr = IPAddress.Parse(MessageIP).GetAddressBytes(); #endif byte[] portArr = BitConverter.GetBytes((ushort)MessagePort); uint[] md5Arr = Tools.MD5StringToUIntArray(updateFileMd5); using (var stream = new MemoryStream()) { stream.Seek(headerSize, SeekOrigin.Begin); stream.Write(BitConverter.GetBytes(md5Arr[0]), 0, 4); stream.Write(BitConverter.GetBytes(md5Arr[1]), 0, 4); stream.Write(BitConverter.GetBytes(md5Arr[2]), 0, 4); stream.Write(BitConverter.GetBytes(md5Arr[3]), 0, 4); stream.Write(BitConverter.GetBytes(blockNum), 0, 2); stream.Write(ipArr, 0, ipArr.Length); stream.Write(portArr, 0, portArr.Length); stream.Write(new byte[] { 0, 0 }, 0, 2); //填充 SystemHeader stream.Seek(0, SeekOrigin.Begin); systemHeader.FrameLength = (ushort)stream.Length; systemHeader.FrameNo = 0xFFFF; byte[] headerData = StructConverter.StructToBytes(systemHeader); stream.Write(headerData, 0, headerData.Length); return stream.ToArray(); } } /// /// 解码 UpdateHostPacketReply /// /// /// /// private UpdateConfigPacketReply? DecodeUpdateConfigPacketReply(byte[] data, int startIndex) { return StructConverter.BytesToStruct(data, startIndex, typeof(UpdateConfigPacketReply)) as UpdateConfigPacketReply?; } #endregion } }