Chinaunix首页 | 论坛 | 博客
  • 博客访问: 18832
  • 博文数量: 8
  • 博客积分: 190
  • 博客等级: 入伍新兵
  • 技术积分: 90
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-14 12:40
文章分类
文章存档

2012年(8)

我的朋友

分类: LINUX

2012-11-14 14:30:12

3. Download Client

 

 

实际上客户端的东西跟下载服务器没有太大的关系了,但是你总得对服务进行测试吧,人不能太懒了.更重要的是你不能说你利用框架搭了一个下载服务器,就说明它是OK的吧.(,,我们大家一起来验证一下...代码如下...我发现,客户端反而复杂了一点..)

客户端所做的事情如下:

  • 接收一个任务,请求该任务的文件大小
  • 将文件划分成若干数据块(分片任务:TaskManager模块),将每个分片分配到下载线程池下载(下载模块:DownloadThread模块)
  • 下载完所有分片后合并成一个完整的文件 (请再次原谅我没有做这一步)

一、生成框架代码

enetlib -s TaskManager

enetlib -s DownloadManager

 

二、任务管理器TaskManager

任务管理器其实是一个线程,用来接收任务,向服务器请求文件大小,然后将文件划分成分片任务提交给下载线程池,由下载线程池完成分片的下载任务.任务管理器还从Netnterface派生,实现协议的发送和接收.

我们需要稍微修改一下TaskManager,使其从PipeThread派生并实现Thread相应的接口方法:

class TaskManager: public NetInterface, public PipeThread

{

protected:

       //实现接口:线程实际运行的入口

       void run_thread();

       //实现接口:响应添加任务事件

       bool on_notify_add_task();

       //实现接口:注册管道事件

       bool register_notify_handler(int write_pipe, EVENT_TYPE event_type, EventHandler* event_handler);

….

};

 

三、下载管理器:DownloadManager

下载管理线程要做的事情主要有:

(1) 接收TaskManager发送过来的下载任务

(2) 从队列里面获取一个任务进行下载.

(3) 下载完后跳到step 2. (即每个线程一次只下载一个分片任务)

 

同TaskManager一样, 稍微修改一下使其从PipeThread派生并实现Thread相应的接口方法:

class DownloadThread:public NetInterface, public PipeThread<DownloadTask* >

{

protected:

       //实现接口:线程实际运行的入口

       void run_thread();

       //实现接口:响应添加任务事件

       bool on_notify_add_task();

       //实现接口:注册管道事件

       bool register_notify_handler(int write_pipe, EVENT_TYPE event_type, EventHandler* event_handler);

...

};

 

1. 接收任务

下载线程收到任务时,会收到on_notify_add_task的通知(怎么收呢?,框架帮你做了),在这里面我们发送一个下载任务,即发送一个RequestData请求.

bool DownloadThread::on_notify_add_task()
{
        SLOG_DEBUG
("Thread[ID=%d,Addr=%x] do task",get_id(), this);
       
return send_download_task();
}
bool DownloadThread::send_download_task(SocketHandle socket_handle)
{
       
if(m_is_downloading)  //一次只执行一个下载任务
               
return false;

       
DownloadTask* download_task = NULL;
       
if(get_task(download_task) && send_download_task(socket_handle, download_task))
                m_is_downloading
= true;
       
return true;
}

 

2. 接收数据

同样,还是在on_recv_protocol里面处理啦,都不用说的啦... 在接收完数据后, 会调用send_download_task来发送下一个分片任务的请求.

 

int DownloadThread::on_recv_protocol(SocketHandle socket_handle, Protocol *protocol)
{
       
switch(((DefaultProtocol*)protocol)->get_type())
       
{
       
case PROTOCOL_RESPOND_DATA: //接收数据
       
{
               
RespondData* temp_protocol = (RespondData*)protocol;
               
const string file_name = temp_protocol->get_file_name();
               
unsigned long long start_pos = temp_protocol->get_start_pos();
               
unsigned int size = temp_protocol->get_size();
               
string data = temp_protocol->get_data();

                ostringstream temp
;
                temp
<<file_name<<"_"<<start_pos;
               
DownloadMap::iterator it = m_downloading_task.find(temp.str());
               
if(it == m_downloading_task.end())
               
{
                        SLOG_WARN
("receive RespondData[file=%s, start=%ld], but can't not find task", file_name.c_str(), start_pos);
               
}
               
else
               
{
                       
DownloadTask* task = it->second;
                        SLOG_INFO
("receive RespondData[fd=%d, file=%s, index=%d, start_pos=%ld, size=%d]", socket_handle, file_name.c_str(), task->task_index, start_pos, size);
                       
if(task->fp == NULL)
                       
{
                               
char buf[128];
                                sprintf
(buf, "%s.%d", task->file_name.c_str(), task->task_index);
                                task
->fp = fopen(buf, "wb");
                       
}

                        fwrite
(data.c_str(), 1, data.size(), task->fp);
                        task
->down_size += data.size();
                       
if(task->down_size == task->size)
                       
{
                                SLOG_INFO
("finish download[fd=%d, file=%s, index=%d]", socket_handle, file_name.c_str(), task->task_index);
                                fclose
(task->fp);
                               
delete task;
                                m_downloading_task
.erase(it);
                                m_is_downloading
= false;
                                send_download_task
(socket_handle); //请求下个任务
                       
}
               
}
               
break;
       
}
       
default:
                SLOG_WARN
("receive undefine protocol. ignore it.");
               
break;
       
}

       
return 0;
}

 

到此我们的下载客户端已经完成了,具体例子详见源码.

阅读(294) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~