private void tcpClient_PacketReceived(object sender, TcpSessionEventArgs e) { object obj = Factory.CreateInstanceObject(e.Data); ImageFileMsg fileMsg = obj as ImageFileMsg; if (fileMsg != null) //如果收到的消息对像不为空 { if (fileMsg.type == type.New) //服务器允许上传文件 { OnFileTransmitBefore(); } //触发文件传输前事件 else if (fileMsg.type == type.set) { TCPSendFile(fileMsg); } //发送文件到服务器 else if (fileMsg.type == type.get) { ReceivedFileBlock(fileMsg); } else if (fileMsg.type == type.over)//文件传输结束 { Console.WriteLine("over!"); OnFileTransmitted();//触发文件传输完成事件 } } }
/// <summary> /// TCP发送消息到文件代理服务器 /// </summary> /// <param name="e"></param> protected void TCPSendMsg(Element e) { if (ServerEP != null && tcpClient.IsConnected) { if (e is ImageFileMsg) { ImageFileMsg finfo = e as ImageFileMsg; finfo.MD5 = TFileInfo.MD5; finfo.Extension = TFileInfo.Extension; } tcpClient.TcpStream.WriteLine(Factory.CreateXMLMsg(e)); } }
/// <summary> /// 处理对方发送文件数据块 /// </summary> private void ReceivedFileBlock(ImageFileMsg fileMsg) //当对方发送文件数据块过来 { if (fileMsg.LastLength > currGetPos) //如果发送过来的数据大于当前获得的数据 { if (CurrRecLength % maxReadWriteFileBlock == 0) { CurrRecLength = 0;//断点清零,重新记忆 if (fileBlock == null) { fileBlock = new byte[maxReadWriteFileBlock]; } if ((TFileInfo.Length - currGetPos) < maxReadWriteFileBlock)//如果是最后一次读写文件,则将所有文件尾数据全部读入到内存 { fileBlock = new byte[TFileInfo.Length - currGetPos]; } } long offSet = CurrRecLength % maxReadWriteFileBlock; // 获得要读写内存的绝对位置 Buffer.BlockCopy(fileMsg.fileBlock, 0, fileBlock, (int)offSet, fileMsg.fileBlock.Length); //将其保存于Buffer字节数组 currGetPos = fileMsg.LastLength; CurrRecLength += fileMsg.fileBlock.Length;//进行断点续传的继点记忆 if (CurrRecLength % maxReadWriteFileBlock == 0 || currGetPos == TFileInfo.Length) { ////////////////////////文件操作 FS = new FileStream(TFileInfo.fullName, FileMode.Append, FileAccess.Write, FileShare.Read); FS.Write(fileBlock, 0, fileBlock.Length); FS.Flush(); FS.Close(); FS.Dispose(); /////////////////////////// } TFileInfo.CurrLength = currGetPos; //设置当前已传输位置 OnFileTransmitting(); //触发收到或发送文件数据事件 if (currGetPos == TFileInfo.Length) //如果文件传输完成,触发传输完成事件 { return; //文件传输 } RequestSendFilePak();//请求对方发送文件的下一数据包 } }
/// <summary> /// 请求发送文件数据包 /// </summary> private void RequestSendFilePak() { ImageFileMsg fileMsg = new ImageFileMsg(); fileMsg.type = type.get; //标识下载 fileMsg.LastLength = currGetPos; fileMsg.MD5 = TFileInfo.MD5; //要下载的文件MD5值 TCPSendMsg(fileMsg); //请求服务器发送文件数据 #region 超时 时间计数器 int TimeCount = 0; if (timer1 == null) { timer1 = new System.Timers.Timer(); timer1.Interval = 5000; timer1.Elapsed += delegate(object sender, System.Timers.ElapsedEventArgs e) { TimeCount++; if (fileMsg.LastLength == currGetPos && TimeCount <= 2)//如果5秒内还未获得新数据包 { //终止发送,并触发获得主机事件 timer1.Enabled = false; TimeCount = 0; if (fileMsg.LastLength == currGetPos)//如果超时 { OnFileTransmitOutTime(); Console.WriteLine("超时:"); } } else if (TimeCount > 2) { timer1.Enabled = false; TimeCount = 0; Console.WriteLine("停止超时检测"); } }; } timer1.Enabled = true; #endregion }
private void tcpClient_Connected(object sender, EventArgs e) { Console.WriteLine("tcpClient_Connected!"); IsConnected = true; //标记已经连接到服务器 OnFileTransmitConnected(); //触发文件传输TCP连接成功事件 if (IsSend) //如果是上传文件 { ImageFileMsg fileMsg = new ImageFileMsg(); fileMsg.Name = TFileInfo.Name; fileMsg.Length = TFileInfo.Length; fileMsg.Extension = TFileInfo.Extension; fileMsg.type = type.New; TCPSendMsg(fileMsg); } else { RequestSendFilePak();//如果是下载文件,则开始下载 } }
/// <summary> /// TCP发送文件 /// </summary> /// <param name="fileMsg"></param> protected void TCPSendFile(ImageFileMsg fileMsg) { long currLength = fileMsg.LastLength; if (currLength >= TFileInfo.Length) { OnFileTransmitted(); //触发文件传输结束事件 return; //如果对方要求发送的数据块起始位置大于文件尺寸则认为是非法请求退出 } if (!isTransmit) { isTransmit = true; //标记文件传输中 OnFileTransmitBefore(); //触发文件开始传输前事件 } #region 如果当前是需要读写文件 if (CurrRecLength % maxReadWriteFileBlock == 0) { CurrRecLength = 0;//断点清零,重新记忆 if (fileBlock == null) { fileBlock = new byte[maxReadWriteFileBlock]; } //读文件到内存过程 if ((TFileInfo.Length - currLength) < maxReadWriteFileBlock)//如果是最后一次读写文件,则将所有文件尾数据全部读入到内存 { fileBlock = new byte[TFileInfo.Length - currLength]; } ////////////////////////文件操作 FS = new FileStream(TFileInfo.fullName, FileMode.Open, FileAccess.Read, FileShare.Read); FS.Seek(currLength, SeekOrigin.Begin);//上次发送的位置 FS.Read(fileBlock, 0, fileBlock.Length); FS.Close(); FS.Dispose(); /////////////////////////// } #endregion long offSet = CurrRecLength % this.maxReadWriteFileBlock;// 获得要发送的绝对位置 //byte[] buffer; if (offSet + mtu > fileBlock.Length) { buffer = new byte[fileBlock.Length - offSet];//要发送的缓冲区 } //else // buffer = new byte[mtu];//要发送的缓冲区 Buffer.BlockCopy(fileBlock, (int)offSet, buffer, 0, buffer.Length);//将其保存于Buffer字节数组 currLength += buffer.Length; CurrRecLength += buffer.Length; //断点设置 fileMsg.type = type.set; //上传标记 fileMsg.LastLength = currLength; fileMsg.fileBlock = buffer; // TCPSendMsg(fileMsg); //发送文件到服务器 TFileInfo.CurrLength = currLength; OnFileTransmitting();//触发收到或发送文件数据事件 }
/// <summary> /// 文件传送 /// </summary> /// <param name="FileTransmit"></param> /// <param name="session"></param> private void onFileTransmit(ImageFileMsg FileMsg, TCPServerSession session) { if (FileMsg.Length > 1024000 || FileMsg.Length < 0) { return; //如果所传输的文件大于1M或无大小则为非法请求退出 } ServerImage image = getServerImage(FileMsg.MD5); string fullFileName = System.Windows.Forms.Application.StartupPath + "\\Images\\" + FileMsg.MD5 + FileMsg.Extension;//标记文件路径 #region 在内存中为文件创建空间 if (FileMsg.type == type.New) //上传文件请求 { if (image == null) //如果服务器内存中无此文件 { image = new ServerImage(FileMsg.MD5); //创建内存文件 Images.Add(image.MD5, image); //将内存文件添加到文件下载服务区 if (File.Exists(fullFileName)) //如果文件已在服务器硬盘中 { image.Data = OpFile.Read(fullFileName); //将文件数据全部读取到内存 image.Length = image.Data.Length; //设置准确的文件长度 image.uploadLength = image.Length; //标记文件已经全部上传完成 FileMsg.type = type.over; //标识文件已经传输完成,通知客户端停止上传 sendFileMsg(FileMsg, session); //通知客户端文件已经上传完成 session.Disconnect(); //断开客户端的TCP连接 } else { image.Extension = FileMsg.Extension; image.Length = FileMsg.Length; image.Name = FileMsg.Name; image.userID = FileMsg.from; image.Data = new byte[image.Length]; //创建内存空间 FileMsg.type = type.set; //通知客户端上传 FileMsg.LastLength = 0; //上传位置从零开始 sendFileMsg(FileMsg, session); //通知客户端可以上传文件 } } else//如果服务器内存中有此文件 { FileMsg.type = type.over;//标识文件已经传输完成,通知客户端停止上传 sendFileMsg(FileMsg, session); //通知客户端文件已经上传完成 session.Disconnect(); //断开客户端的TCP连接 } } #endregion #region 载文件 if (FileMsg.type == type.get) //下载文件请求 { if (image == null) //如果内存中无文件 { if (File.Exists(fullFileName)) //如果文件已在服务器硬盘中 { image = new ServerImage(FileMsg.MD5); //创建内存文件 image.MD5 = FileMsg.MD5; image.Data = OpFile.Read(fullFileName); //将文件数据全部读取到内存 image.Length = image.Data.Length; //设置准确的文件长度 image.uploadLength = image.Length; //标记文件已经全部上传完成 Images.Add(image.MD5, image); //将内存文件添加到文件下载服务区 } } if (image != null && FileMsg.LastLength < image.Data.Length) //如果内存中有文件 { if (FileMsg.LastLength + 10240 > image.Data.Length) { FileMsg.fileBlock = new byte[image.Data.Length - FileMsg.LastLength];//要发送的缓冲区 } else { FileMsg.fileBlock = new byte[10240]; //要发送的缓冲区 } Buffer.BlockCopy(image.Data, (int)FileMsg.LastLength, FileMsg.fileBlock, 0, FileMsg.fileBlock.Length); //将其保存于Buffer字节数组 FileMsg.type = type.get; //下载标记 FileMsg.LastLength += FileMsg.fileBlock.Length; sendFileMsg(FileMsg, session); if (FileMsg.LastLength == image.Data.Length) { FileMsg.type = type.over;//标记下载完成 FileMsg.fileBlock = null; sendFileMsg(FileMsg, session); session.Disconnect(); } } } #endregion #region 文件 if (FileMsg.type == type.set)//上传文件内容 { if (image.uploadLength + FileMsg.fileBlock.Length > image.Length) { return; } Buffer.BlockCopy(FileMsg.fileBlock, 0, image.Data, (int)image.uploadLength, FileMsg.fileBlock.Length); //将收到的数据保存于Buffer字节数组 image.uploadLength += FileMsg.fileBlock.Length; //设置最后一次上传文件的末尾长度 FileMsg.LastLength = image.uploadLength; //告诉客户端已上传的文件位置 FileMsg.fileBlock = null; if (image.uploadLength == image.Length)//如果文件上传完成 { OpFile.Write(image.Data, fullFileName); FileMsg.type = type.over; //标识文件已经传输完成,通知客户端停止上传 sendFileMsg(FileMsg, session); //通知客户端文件已经上传完成 session.Disconnect(); //断开客户端的TCP连接 } else { sendFileMsg(FileMsg, session);//通知客户端上传文件下一数据包 } } #endregion }