using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Text; using System.Threading; namespace DllFileSoc { public class DllSocketFile { public byte[] UploadFile(SocketFileEntity sfe, SocketEntity se,ref string errorinfo) { Socket filesocket = null; try { if (string.IsNullOrEmpty(sfe.ClientFilePath)|| string.IsNullOrEmpty(se.MacCode)) { return GetFileDatas(1, -1, "初始化异常,未能取到本机文件目录或机台编号!"); } filesocket = ConnServer(sfe, ref errorinfo); if (filesocket == null) { return GetFileDatas(1, -1, errorinfo); } else { } if (!string.IsNullOrEmpty(sfe.ClientFilePath)&& !string.IsNullOrEmpty(sfe.FileName)) { //创建一个文件对象 FileInfo EzoneFile = new FileInfo(sfe.ClientFilePath + Path.DirectorySeparatorChar + sfe.FileName); //打开文件流 FileStream EzoneStream = EzoneFile.OpenRead(); //EzoneStream.Position = 0; long size = EzoneStream.Length; byte[] array = new byte[size];//文件 EzoneStream.Read(array, 0, array.Length); string md5 = GetMD5HashFromFile(array); EzoneStream.Close(); EzoneStream = null; EzoneFile = null; byte[] datas = GetFileDatas(1,md5,se); filesocket.Send(datas);//发送文件md5包到服务器进行验证 int alllen = 0; datas = ReadData(filesocket, ref alllen, ref errorinfo);//接收反馈包 if (datas == null) return GetFileDatas(1, -1, errorinfo); //byte[] tempstr = new byte[alllen - 32]; //Array.Copy(datas, 32, tempstr, 0, tempstr.Length); byte[] statusdatas = new byte[4]; Array.Copy(datas, 8, statusdatas, 0, 4); //Array.Reverse(statusdatas);//20200920 int status = BitConverter.ToInt32(statusdatas, 0); //if (status == 1 ||status==-1) // return datas; if (status == 2)//需要上传文件 { datas = GetFileDatas(array); //int sendlen=filesocket.Send(datas);//发送文件内容 if(!SendData(filesocket,datas,ref errorinfo)) return GetFileDatas(1, -1, errorinfo); datas = ReadData(filesocket, ref alllen, ref errorinfo);//接收反馈包 } if(datas==null) return GetFileDatas(1, -1, errorinfo); return datas; } else { return GetFileDatas(1, -1, "本地查找不到文件,上传失败"); } } catch (Exception ex) { errorinfo = ex.Message.ToString(); return GetFileDatas(1, -1, errorinfo); } finally { if (filesocket != null) filesocket.Close(); } } public byte[] DownloadFile(SocketFileEntity sfe, SocketEntity se, ref string errorinfo) { Socket filesocket = null; try { //sfe.ClientFilePath = "D:\\SocketClientFile"; //se.MacCode = "XX001"; if (string.IsNullOrEmpty(sfe.ClientFilePath) || string.IsNullOrEmpty(se.MacCode)) { return GetFileDatas(2, -1, "初始化异常,未能取到本机文件目录或机台编号!"); } filesocket = ConnServer(sfe,ref errorinfo); if (filesocket == null) { return GetFileDatas(1, -1, errorinfo); } string md5 = "error"; //创建一个文件对象 string path = sfe.ClientFilePath + Path.DirectorySeparatorChar + sfe.FileName; FileInfo EzoneFile = new FileInfo(path); if (File.Exists(path)) { //打开文件流 FileStream EzoneStream = EzoneFile.OpenRead(); long size = EzoneStream.Length; byte[] array = new byte[size];//文件 EzoneStream.Read(array, 0, array.Length); md5 = GetMD5HashFromFile(array); EzoneStream.Close(); EzoneStream = null; EzoneFile = null; } int alllen = 0; //byte[] datas = GetFileDatas(2,sfe.FileName); byte[] datas = GetFileDatas(2,md5, sfe.ServerFileFullPath, sfe.FileName); filesocket.Send(datas);//发送下载指令包 //int md5Result = CheckClentMD5(filesocket, sfe.ClientFilePath, sfe.FileName, ref errorinfo); //if (md5Result ==1)//说明本地有相同文件 //{ // datas = GetFileDatas(2, 3, "End To DownLoad"); // filesocket.Send(datas);//发送不需要下载的指令 // return GetFileDatas(2, 1, "该文件[" + sfe.FileName + "]本地目录下已存在,无需下载!"); //} //else //{ // datas = GetFileDatas(2, 1, "Begin To DownLoad"); // filesocket.Send(datas);//发送需要下载的指令 //} //接收反馈包(需要下载时) datas = ReadData(filesocket, ref alllen, ref errorinfo); byte[] statusdatas = new byte[4]; Array.Copy(datas, 8, statusdatas, 0, 4); //Array.Reverse(statusdatas); int status = BitConverter.ToInt32(statusdatas, 0); if (status == 3)//本地已有相同MD5的文件,无需下载 return GetFileDatas(2, 1, "本地已有文件[" + sfe.FileName + "],无需下载!"); if (status == 1)//成功则写入本地文件 { //string fileName = System.IO.Path.GetFileName(sfe.FileName); byte[] filebytes = new byte[alllen - 12]; Array.Copy(datas, 12, filebytes, 0, alllen-12); FileStream MyFileStream = new FileStream(sfe.ClientFilePath + Path.DirectorySeparatorChar + sfe.FileName, FileMode.Create, FileAccess.Write); MyFileStream.Write(filebytes, 0, filebytes.Length); MyFileStream.Close(); MyFileStream = null; datas = GetFileDatas(2, 1, "文件[" + sfe.FileName + "]下载成功!"); //errorinfo = "文件[" + sfe.FileName + "]下载成功!"; } //else //{ // datas = GetFileDatas(2, -1, "文件[" + sfe.FileName + "]下载失败!"); // //errorinfo = "文件[" + sfe.FileName + "]下载失败!"; //} if (datas == null) return GetFileDatas(1, -1, errorinfo); return datas; } catch (Exception ex) { errorinfo = ex.Message.ToString(); return GetFileDatas(2,-1,errorinfo); } finally { if (filesocket != null) filesocket.Close(); } } public byte[] GetMacFileList(SocketFileEntity sfe, SocketEntity se, ref string errorinfo) { try { string filedir = sfe.ClientFilePath; DirectoryInfo root = new DirectoryInfo(filedir); FileInfo[] files = null; if(sfe.FileName==null||sfe.FileName.Trim()=="") { files = root.GetFiles(); } else { files = root.GetFiles().Where(t => t.Name.Contains(sfe.FileName)).ToArray(); } List fileslist = new List(); foreach(var item in files) { fileslist.Add(item.Name); } return GetFileDatas(3, 1, fileslist); } catch (Exception ex) { errorinfo = ex.Message.ToString(); return GetFileDatas(3, -1, errorinfo); } } private Socket ConnServer(SocketFileEntity sfe,ref string errorinfo) { try { IPAddress ip = IPAddress.Parse(sfe.ConnetIp);//服务端所在IP //IPEndPoint ipEnd = new IPEndPoint(ip, 5888);//服务端所监听的接口 IPEndPoint ipEnd = new IPEndPoint(ip, sfe.ConnetPort);//服务端所监听的接口 Socket CurrSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//初始化一个Socket对象 CurrSocket.Connect(ipEnd); //此语句只支持windows系统,不支持linux系统 //CurrSocket.IOControl(IOControlCode.KeepAliveValues, GetKeepAliveData(), null); ////处理来自机台的包,设置接受超时时间 CurrSocket.ReceiveTimeout = sfe.SetTimeOut; CurrSocket.SendTimeout = sfe.SetTimeOut; return CurrSocket; } catch (Exception ex) { errorinfo = ex.Message.ToString(); return null; } } private int CheckClentMD5(Socket filesocket, string filePath,string fileName,ref string errorinfo) { try { FileInfo EzoneFile = new FileInfo(filePath + Path.DirectorySeparatorChar + fileName); if (EzoneFile == null) return -1; FileStream EzoneStream = EzoneFile.OpenRead(); long size = EzoneStream.Length; byte[] array = new byte[size];//文件 EzoneStream.Read(array, 0, array.Length); string clientMd5 = GetMD5HashFromFile(array); int allen = 0; byte[] datas = ReadData(filesocket, ref allen, ref errorinfo); byte[] fileMd5 = new byte[datas.Length - 4]; Array.Copy(datas, 4, fileMd5,0, fileMd5.Length); string serverMd5 = Encoding.UTF8.GetString(fileMd5); if (clientMd5== serverMd5) { return 1; } else { return -1; } } catch (Exception ex) { errorinfo = ex.Message.ToString(); return -1; } } /// /// 带有MD5验证的包 /// /// /// /// /// private byte[] GetFileDatas(Int32 mode, string md5,SocketEntity se) { Dictionary dic = new Dictionary(); byte[] msgbytes = Encoding.UTF8.GetBytes(md5); dic.Clear(); dic.Add("fileName",se.FileName); dic.Add("macCode", se.MacCode); byte[] bytese = SerializeBytes>(dic); //byte[] bytese= SerializeBytes(se); Int32 len = bytese.Length + 40; byte[] alldatas = BitConverter.GetBytes(len); byte[] forAll= (alldatas.Concat(BitConverter.GetBytes(mode)).Concat(msgbytes).Concat(bytese)).ToArray(); //SocketEntity sockE = DeSerializeBytes(bytese); return forAll; } private byte[] GetFileDatas(Int32 mode, string md5,string fullpath,string filename) { Dictionary dicFile = new Dictionary(); dicFile.Add("clientMd5", md5); dicFile.Add("serverFullpath", fullpath); dicFile.Add("serverFilename", filename); byte[] msgbytes = SerializeBytes>(dicFile); //byte[] filefullpath = Encoding.UTF8.GetBytes(fullpath); Int32 len = msgbytes.Length + 8; byte[] alldatas = BitConverter.GetBytes(len); byte[] forAll = (alldatas.Concat(BitConverter.GetBytes(mode)).Concat(msgbytes)).ToArray(); //SocketEntity sockE = DeSerializeBytes(bytese); return forAll; } private byte[] GetFileDatas( byte[] files) { //byte[] msgbytes = Encoding.UTF8.GetBytes(msg); Int32 len = files.Length + 4; byte[] alldatas = BitConverter.GetBytes(len); byte[] forAll= (alldatas.Concat(files)).ToArray(); return forAll; } private byte[] GetFileDatas(Int32 mode, string filename) { byte[] files = Encoding.UTF8.GetBytes(filename);//文件名 Int32 len = files.Length +8; byte[] alldatas = BitConverter.GetBytes(len);//总长度 byte[] md = BitConverter.GetBytes(mode);//指令 byte[] forAll = (alldatas.Concat(BitConverter.GetBytes(mode)).Concat(files)).ToArray(); //return alldatas; //byte[] all = new byte[len]; //Array.Copy(alldatas, 0, all, 0,4); //Array.Copy(md, 0, all, 4, 4); //Array.Copy(files, 0, all, 8, files.Length); return forAll; } private byte[] GetFileDatas(Int32 mode, Int32 result, string msg) { byte[] msgbytes = Encoding.UTF8.GetBytes(msg); Int32 len = msgbytes.Length + 12; byte[] alldatas = BitConverter.GetBytes(len); byte[] forAll = (alldatas.Concat(BitConverter.GetBytes(mode)).Concat(BitConverter.GetBytes(result)).Concat(msgbytes)).ToArray(); return forAll; } private byte[] GetFileDatas(Int32 mode, Int32 result, List msg) { byte[] msgbytes = SerializeBytes>(msg); Int32 len = msgbytes.Length + 12; byte[] alldatas = BitConverter.GetBytes(len); byte[] forAll = (alldatas.Concat(BitConverter.GetBytes(mode)).Concat(BitConverter.GetBytes(result)).Concat(msgbytes)).ToArray(); return forAll; } //socket读取数据 private byte[] ReadData(Socket CurrSocket, ref int alllen, ref string errorinfo) { byte[] allbuffs = null; try { byte[] tempbuff = new byte[4]; byte[] bytesbuff = new byte[4]; int result = 0; int levlen = 4; int zerocount = 0; while (levlen > 0) { //说明前面4位还没接受完,需要继续接受 result = CurrSocket.Receive(tempbuff, levlen, SocketFlags.None);//先读取4位块长度字节 if (result == 0 && zerocount <= 20) { zerocount++; //如果返回数据长度为0,则休眠1秒钟,然后继续读取 Thread.Sleep(1000); continue; } if (result <= 0) { errorinfo = $"未能从待机程序监听上读取数据,可能机台已经断开了,接受长度={result} "; return null; } if (result < levlen) { //添加测试代码 //int a = 10; } if (result > 0) { Array.Copy(tempbuff, 0, bytesbuff, 4 - levlen, result); } levlen = levlen - result; } //Array.Reverse(bytesbuff);//20200920 int len = BitConverter.ToInt32(bytesbuff, 0)-4; alllen = len; if (len > 10) { int a = 10; } byte[] buffs = new byte[len]; tempbuff = new byte[len]; levlen = len; zerocount = 0; while (levlen > 0) { //说明还没接受完,需要继续接受 result = CurrSocket.Receive(tempbuff, levlen, SocketFlags.None); if (result == 0 && zerocount <= 20) { zerocount++; //如果返回数据长度为0,则休眠1秒钟,然后继续读取 Thread.Sleep(1000); continue; } if (result <= 0) { errorinfo = $"未能从待机程序监听上读取数据,可能机台已经断开了,接受长度={result} "; return null; } if (result > 0) { Array.Copy(tempbuff, 0, buffs, len - levlen, result); } levlen = levlen - result; } //result =mysocket.Receive(buffs,len,SocketFlags.None); //Array.Reverse(bytesbuff);//20200920 allbuffs = new byte[len + 4]; Array.Copy(bytesbuff, allbuffs, 4); Array.Copy(buffs, 0, allbuffs, 4, len); alllen = len + 4; return allbuffs; } catch (SocketException ex) { errorinfo = "待机程序Socket接受数据发生异常,错误信息为:" + ex.SocketErrorCode.ToString(); return null; } catch (Exception ex) { errorinfo = ex.Message.ToString(); errorinfo = "待机程序Socket接受数据发生异常,错误信息为:" + errorinfo; return null; } } private bool SendData(Socket CurrSocket,byte[] allbytes,ref string errorinfo) { try { //包的大小 1MB int PacketSize = 1024*1024; //包的数量 int PacketCount = (int)(allbytes.Length / ((long)PacketSize)); //最后一个包的大小 int LastDataPacket = (int)(allbytes.Length - ((long)(PacketSize * PacketCount))); int satrtNum = 1; int len = PacketCount; byte[] sendArr = null; while (len > 0) { sendArr = new byte[PacketSize]; Array.Copy(allbytes, (satrtNum - 1) * PacketSize, sendArr, 0, PacketSize); //CurrSocket.Send(sendArr);//发送文件内容 if (!SendDataIt(CurrSocket, sendArr, ref errorinfo)) return false; len = len - 1; satrtNum++; } if (LastDataPacket!=0) { sendArr = new byte[LastDataPacket]; Array.Copy(allbytes, PacketCount * PacketSize, sendArr, 0, LastDataPacket); //CurrSocket.Send(sendArr);//发送最后一个包 if (!SendDataIt(CurrSocket, sendArr, ref errorinfo)) return false; } return true; } catch (SocketException ex) { errorinfo = "待机程序Socket发送数据发生异常,错误信息为:" + ex.SocketErrorCode.ToString(); return false; } catch (Exception ex) { errorinfo = ex.Message.ToString(); errorinfo = "待机程序Socket发送数据发生异常,错误信息为:" + errorinfo; return false; } } private bool SendDataIt(Socket CurrSocket, byte[] allbytes, ref string errorinfo) { try { int lenlev = allbytes.Length; byte[] tempbytes = null; int result = 0; while (lenlev > 0) { tempbytes = new byte[lenlev]; Array.Copy(allbytes,allbytes.Length-lenlev, tempbytes, 0, lenlev); result=CurrSocket.Send(tempbytes);//发送文件内容 lenlev = lenlev - result; } return true; } catch (SocketException ex) { errorinfo = "Socket发送数据发生异常,错误信息为:" + ex.SocketErrorCode.ToString(); return false; } catch (Exception ex) { errorinfo = ex.Message.ToString(); errorinfo = "Socket发送数据发生异常,错误信息为:" + errorinfo; return false; } } public static string GetMD5HashFromFile(byte[] filedatas) { try { System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); byte[] retVal = md5.ComputeHash(filedatas); StringBuilder sb = new StringBuilder(); for (int i = 0; i < retVal.Length; i++) { sb.Append(retVal[i].ToString("x2")); } return sb.ToString(); } catch (Exception ex) { //errorinfo = ex.Message.ToString(); return ""; } } public static T DeSerializeBytes(byte[] bytes) where T : class { MemoryStream stream = new MemoryStream(bytes); IFormatter formatter = new BinaryFormatter(); stream.Seek(0, SeekOrigin.Begin); T o = (T)formatter.Deserialize(stream); stream.Close(); return o; } /// /// 将实体序列化 /// /// /// /// public static byte[] SerializeBytes(T obj) where T : class { MemoryStream stream = new MemoryStream(); IFormatter formatter = new BinaryFormatter(); formatter.Serialize(stream, obj); stream.Close(); return stream.ToArray(); } } }