您的位置:首页 > 其它

ESFramework Demo -- 文件传送Demo(附源码)

2011-10-25 16:49 387 查看
现在我们将在ESFramework 开发手册(11) -- 入门Demo,简单的即时通讯系统 的基础上,使用ESPlus提供的第三个武器,为其增加文件传送的功能。在阅读本文之前,请务必先掌握ESFramework 开发手册(03) -- 文件(夹)传送 一文中介绍的文件传送的流程及相关的API的用法。
本文的demo仅仅实现了客户端与客户端之间的文件传送,至于传送文件夹,以及服务器与客户端之间的文件传送则采用完全一样的模型,大家可以在本demo的基础上自行扩展。
本Demo演示以下与文件传送相关的特性:
(1)发送方请求发送文件,接收方可以同意或拒绝接收文件。
(2)文件传送的过程中,收发的任何一方都可以通过事件了解文件传送的实时进度。
(3)文件传送的过程中,收发的任何一方都可以中断文件的传送。
(4)文件传送的过程中,收发的任何一方掉线,都将导致文件传送中断。
(5)只要文件传送中断,收发方都会得到相应的事件通知。
(6)自动启用文件断点续传。
(7)文件传送完成,收发方都会得到相应的事件通知。

一.服务端

由于在demo中,服务端不参与文件传送,所以,服务端的代码不用做任何修改,直接使用上一个demo中的服务端即可。
顺便提一下,如果想让服务端作为文件收发的一方,也很容易,只要遵循以下几点:
(1)使用IRapidServerEngine暴露的FileController属性,来控制文件的收发行为。
(2)预定IFileController的FileSendingEvents事件和FileReceivingEvents事件,来跟踪文件传送的实时状态。
(3)服务端的虚拟帐号为NetServer.SystemUserID,即"_0"。当一个文件的接收者的UserID为NetServer.SystemUserID,表示文件是由服务端接收的;当一个文件的发送者的UserID为NetServer.SystemUserID,表示这个文件是由服务端发送的。

二.客户端

相对于上一个demo,客户端改动的地方主要集中在MainForm和ChatForm上。客户端使用IRapidPassiveEngine暴露的FileOutter属性,来控制文件的收发行为。

发送与接收流程实现

首先,ChatForm的最上方增加了一个“发送文件”的按钮,点击此按钮的时候,将选择文件,并请求发送。此时,客户端作为发送方的身份出现。
//请求发送文件         
        private void toolStripButton1_Click(object sender, EventArgs e)  
        {      
            string filePath = ESBasic.Helpers.FileHelper.GetFileToOpen("打开");      
            if (filePath == null)      
            {          
                return;      
            }      
            string fileID;      
            SendingFileParas sendingFileParas = new SendingFileParas(20480, 0);//文件数据包大小,可以根据网络状况设定,局网内可以设为204800,传输速度可以达到30M/s以上;公网建议设定为2048或4096或8192      
            this.fileOutter.BeginSendFile(this.friendID, filePath, null, sendingFileParas, out fileID);  
        }
其次,客户端在MainForm的Initialize方法中通过预定IRapidPassiveEngine的FileOutter的FileRequestReceived事件,来获得接收到了文件传送请求的通知。此时,客户端是作为接收方的身份出现。
//预定收到了来自发送方发送文件(夹)的请求的事件  
        this.rapidPassiveEngine.FileOutter.FileRequestReceived += new CbFileRequestReceived(fileOutter_FileRequestReceived);
注意,FileRequestReceived事件有个ResumedProjectItem类型的参数,用于表示当前传送项目是否能够续传。如果该参数不为null,则表示可以续传;如果该参数为null,则表示是一个全新的传送项目,不能续传。
在该事件的处理函数中,最终会弹出MessageBox,询问用户是否同意接收,如果同意,则选择保存路径。根据用户的操作,我们需要将是否同意接收文件的答案通知给发送方。即ChatForm的OnFileRequest方法:
//当接收到对方的文件传送请求时  
        public void OnFileRequest(string fileID, string senderID, string fileName)  
        {      
            if (DialogResult.OK == MessageBox.Show(string.Format("{0}要求向你传输文件{1},你是否同意接收?", senderID, fileName), "文件传输", MessageBoxButtons.OKCancel))      
            {          
                string savePath = ESBasic.Helpers.FileHelper.GetPathToSave("保存", fileName, null);          
                if (!string.IsNullOrEmpty(savePath))          
                {              
                    this.fileOutter.BeginReceiveFile(fileID, savePath);          
                }          
                else          
                {              
                    this.RejectFile(fileID, fileName);          
                }      
            }      
            else      
            {           
                this.RejectFile(fileID, fileName);      
            }  
        }   
        
        private void RejectFile(string fileID, string fileName)  
        {      
            TransferingProject fileInfo = this.fileOutter.GetTransferingProject(fileID);      
            if (fileInfo != null)      
            {          
                this.textChatControl1.ShowRejectFile(fileName);          
                this.fileOutter.RejectFile(fileID);       
            }  
        }
发送方又是在MainForm的Initialize方法中通过预定IRapidPassiveEngine的FileOutter的FileResponseReceived事件,来得到对方的回复的:
//预定接收方回复了同意/拒绝接收文件(夹)时的事件  
        this.rapidPassiveEngine.FileOutter.FileResponseReceived += new CbGeneric<TransferingProject, bool>(fileOutter_FileResponseReceived);
如果对方同意接收,则ESPlus会在后台自动启动文件发送线程进行文件发送。
客户端无论是作为发送方还是接收方,都在ChatForm中使用了FileTransferingViewer控件来显示各个文件传送项目的实时状态,并且通过预定其状态变化事件来接收通知,然后在聊天窗口中显示相应的信息。

Demo运行起来后,传送文件的截图如下所示:



当关闭聊天窗口ChatForm时,判断当前是否有文件正在传输。如果有,则提醒用户,如果用户仍然决定关闭,则在关闭窗体之前先要取消相关的正在传送的项目。
private void ChatForm_FormClosing(object sender, FormClosingEventArgs e)  
          {      
              List<string> fileIDs = this.fileOutter.GetTransferingAbout(this.friendID);      
              if (fileIDs != null && fileIDs.Count > 0)      
              {         
                  DialogResult result = MessageBox.Show("如果关闭窗口,就会中止文件传送。是否关闭窗口?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.None);          
                  if (result == DialogResult.OK)          
                  {              
                      this.fileOutter.CancelTransferingAbout(this.friendID);          
                  }          
                  else          
                  {              
                      e.Cancel = true;          
                  }      
              }  
          }

断点续传

当文件传送中断(比如因为掉线)后,发送方再次发送该文件,此时如果接收方同意接收,并且保存的路径与上次完全一致,那么框架底层将自动启用断点续传。 发送方和接收方以预定了FileTransferingViewer的FileResumedTransStarted事件,来得知断点续传启动的信息。
更简单的,就像前面提到的,FileRequestReceived事件的ResumedProjectItem类型的参数,如果其值不为null,则表示可以续传。如果用户选择了续传,则就直接使用ResumedProjectItem的LocalSavePath属性的值作为文件存储路径,去调用IFileOutter的BeginReceiveFile方法就可以了。有兴趣的朋友,可以按照这种模式修改一下demo代码,就可以完全达到类似QQ的续传效果。

三.FileTransferingViewer控件

FileTransferingViewer控件用于显示每个文件传送项目的实时状态。与QQ的文件传送的UI相比,FileTransferingViewer只是一个用于demo的简单控件。我们这里将FileTransferingViewer的源码开放给大家,大家可以在其基础上进行修改,以达到自己想要的效果(或与QQ完全一样的效果)。
众多其它细节,已经在ESFramework 开发手册(03) -- 文件(夹)传送 一文中作了详细介绍,这里不再赘述。大家可以参考上文和本文,然后对照源码进行研究,很容易就可以理解内部的运转流程了。

四.源码下载

(1)ESFramework.Demos.FileTransfer 源码
(2)FileTransferingViewer 控件源码

阅读 更多ESFramework开发手册系列文章
-----------------------------------------------------------------------------------------------------------------------------------------------
关于ESFramework的任何问题,欢迎联系我们:
电话:027-87638960
Q Q:372841921
邮件:esframework@oraycn.com
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: