Tcp应用实例---3.从服务端下载文件(断点续传)

(源码下载地址,http://download.csdn.net/source/406996

  要实现断点续传,必须要得到上次的下载信息。这里使用的是最简单的单线程断点续传,因此需要的信息也非常少,在SysConfig.ini中保存了下面三个信息:LastDownFile--最后下载的文件在服务器上的文件名,LastDownFilePath--最后下载的文件在本地保存的路径,LastDownFileLength--最后下载的文件的文件长度。(每次下载文件时,如果要下载的文件和最后一次下载的一样,就进行断点续传,否则重新下载。)
  每当点击“下载文件”按钮,程序先判断左边的列表框中是否选择了文件:  

if  (listBox1.SelectedItem  ==   null )
return ;

 

  然后判断是否最后下载过的文件  如果是,则判断未下载完成的文件是否存在,存在则继续下载:

             string  fileName  =  listBox1.SelectedItem.ToString();
            
if  (fileName  ==  _sysConfig.GetIniString( " LastDownFile " "" ))
            
{
                
if (File.Exists(_sysConfig.GetIniString("LastDownFilePath""")))
                
{
                    DownFile(fileName,
                            _sysConfig.GetIniString(
"LastDownFilePath"""),
                            Convert.ToInt64(_sysConfig.GetIniString(
"LastDownFileLength""0")));
                    
return;
                }

            }

 

  其中下载的过程提交到了函数DownFile中,这个后面再说。

  如果不是上一次下载的,则需要重新下载,首先从服务器得到文件的长度:

     long  fileLength  =  GetFileLength(fileName);
    
if  (fileLength  ==   0 )
        
return ;

 

  如果文件长度为0,则退出下载,返回文件长度的函数是GetFileLength:

         private   long  GetFileLength( string  fileName)
        
{
            TcpClient tcp 
= null;
            NetworkStream stream 
= null;
            
try
            
{
                
建立连接,与发送请求文件长度的命令

                
接收数据

                
转换文件长度

                
return fileLength;
            }

            
catch (Exception ex)
            
{
                MessageBox.Show(ex.Message);
                
return 0;
            }

            
finally
            
{
                
释放
            }

        }


 

  分三个步骤:与服务器建立连接并发送请求文件长度的命令;接收数据;转换数据成文件长度。

  得到文件长度后便建立文件:

     string  destFileName  =  CreateNewFile(fileName);
     
if  (destFileName  ==   "" )
        
return ;

 

  建立文件的过程是由函数CreateNewFile来完成的:

         private   string  CreateNewFile( string  sourceFileName)
        
{
            saveFileDialog1.FileName 
= sourceFileName;
            
if (saveFileDialog1.ShowDialog() == DialogResult.Cancel)
                
return "";

            FileStream s 
= null;
            
try
            
{
                s 
= new FileStream(saveFileDialog1.FileName, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
                s.SetLength(
0);
            }

            
finally
            
{
                
if (s != null)
                    s.Close();
            }


            
return saveFileDialog1.FileName;
        }


 

  最后,控制权也转交到了DownFile函数中:

DownFile(fileName, saveFileDialog1.FileName, fileLength);

 

  DownFile的代码如下:

         private   void  DownFile( string  fileName,  string  path,  long  fileLength)
        
{
            
保存最后下载的信息

            
初始化进度条

            
启动下载线程
        }


 

  它实际上的下载过程是由TclientConnection类的GetFile函数来实现的:

         public   void  GetFile()
        
{
            
定义变量

            
获取当前下载进度

            
判断文件是否已经下载完毕

            
开始下载
        }


 

  GetFile函数先根据本地文件的大小与实际文件的大小得到下载进度,并在进度条上显示出来;然后判断是否下载完毕;如果没有下载完毕,则向服务器发送请求文件的命令,命令的参数是文件名和已接收数据的大小。最后,它接收从服务器返回的数据,写入文件流中。

  在客户端的GetFileLength和GetFile函数中,都是先知道了服务器返回的数据的格式,才好进行接收的。
  下面看服务端的实现。

  首先,服务端要在TserverConnection类的ExtractRecStr中增加两个判断,将请求文件大小、请求文件的命令交给其他函数来处理:

         private   void  ExtractRecStr(TCommand command, NetworkStream stream)
        
{
            
switch (command.commandStyle)
            
{
                
case CommandStyleEnum.cList:
                    OnGetFileList(stream);
                    
break;
                
case CommandStyleEnum.cGetFileLength://请求文件大小
                    OnGetFileLength(command, stream);
                    
break;
                
case CommandStyleEnum.cGetFile://请求文件
                    OnGetFile(command, stream);
                    
break;
                
default:
                    
break;
            }

        }

 

  看向客户端返回文件大小的函数OnGetFileLength:

         private   void  OnGetFileLength(TCommand command, NetworkStream stream)
        
{
            
long fileLength = GetData.GetFileLength((string)command.argList[0]);

            TCommand tempCommand 
= null;
            
if (fileLength == 0)
                tempCommand 
= new TCommand(CommandStyleEnum.cGetFileLengthReturnNone);
            
else
                tempCommand 
= new TCommand(CommandStyleEnum.cGetFileLengthReturn);

            tempCommand.AppendArg(fileLength.ToString());

            
byte[] data = tempCommand.ToBytes();
            stream.Write(data, 
0, data.Length);
        }


 

  它从TCommand类对象的参数argList中取出文件名,然后用类GetData的函数GetFileLength返回文件大小;再根据文件大小生成返回命令,并发送到客户端。

  再看函数OnGetFile:

         private   void  OnGetFile(TCommand command, NetworkStream stream)
        
{
            
根据客户端已下载的字节数来定位文件流

            
try
            
{
                
发送数据
            }

            
catch (Exception)
            
{
            }

            
finally
            
{
                s.Close();
            }

        }


 

  它首先从TCommand的对象中得到客户端已接收的字节数,然后将文件流定位到已发送数据的末尾,最后将剩下的文件以1024长度的字节数组不断地发送到客户端。
  
  Over。
    ie.2008-04-09

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值