2012年(8)
分类: LINUX
2012-11-14 14:17:18
2. Download Server
这一节我们介绍一个多线程下载服务器.
1.服务器收到一个请求时,将该任务分配到某个线程,由该线程处理对应的请求.
2.某个线程收到RequestSize时,返回协议指定file_name返回文件的大小给客户端(回复RespondSize协议).
3.某个线程收到RequestData请求时,按协议指定的数据偏移start_pos请求file_name的size大小的数据块返回给客户端(回复RespondData协议).
一、Download 线程及线程池
1. 用enetlib生成框架代码:
enetlib -m DownloadServer -main
生成了3个文件:
DownloadServer.cpp
DownloadServer.h
DownloadServerMain.cpp
ok, 我们的下载服务器完成了, 收工....开玩笑的, 还需要添加业务逻辑层代码呢:
二、 DownloadServer 线程
1. 实现创建协议族方法:
ProtocolFamily* DownloadServer::create_protocol_family()
{
return new DownloadProtocolFamily;
}
void DownloadServer::delete_protocol_family(ProtocolFamily* protocol_family)
{
delete protocol_family;
}
接下来当然是处理请求协议,来看看我们是如何做到的:当然是实现on_recv_protocol接口了.2. 处理请求协议:
bool DownloadServer::on_recv_protocol(SocketHandle socket_handle, Protocol *protocol, bool &detach_protocol)
{
DownloadProtocolFamily* protocol_family = (DownloadProtocolFamily*)get_protocol_family();
DefaultProtocolHeader *header = (DefaultProtocolHeader *)protocol->get_protocol_header();
switch(header->get_protocol_type())
{
case PROTOCOL_REQUEST_SIZE:
{
RequestSize *temp_protocol = (RequestSize*)protocol;
const string file_name = temp_protocol->get_file_name();
SLOG_INFO("receive
string path="/data/";
path += file_name;
//get file size
unsigned long long file_size=0;
FILE *fp = fopen(path.c_str(), "r");
if(fp != NULL)
{
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
fclose(fp);
}
RespondSize* resp_protocol = (RespondSize*)protocol_family->create_protocol(PROTOCOL_RESPOND_SIZE);
if(resp_protocol)
{
resp_protocol->assign(file_name, file_size);
send_protocol(socket_handle, resp_protocol);
}
else
SLOG_ERROR("create RespondSize protocol failed.");
break;
}
case PROTOCOL_REQUEST_DATA:
{
RequestData *temp_protocol = (RequestData*)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();
SLOG_INFO("receive
string path="/data/";
path += file_name;
FILE *fp = fopen(path.c_str(), "r");
if(fp != NULL)
{
RespondData* resp_protocol = (RespondData*)protocol_family->create_protocol(PROTOCOL_RESPOND_DATA);
resp_protocol->assign(file_name, start_pos, size);
DefaultProtocolHeader *header = (DefaultProtocolHeader *)resp_protocol->get_protocol_header();
int header_length = header->get_header_length();
ByteBuffer *byte_buffer = new ByteBuffer;
//1. 预留协议头空间
byte_buffer->get_append_buffer(header_length);
byte_buffer->set_append_size(header_length);
//2. 编码协议体数据
resp_protocol->encode_body(byte_buffer);
//3. 添加数据
char *data_buffer = byte_buffer->get_append_buffer(size);
fseek(fp, start_pos, SEEK_SET);
fread(data_buffer, 1, size, fp);
fclose(fp);
byte_buffer->set_append_size(size);
//4. 编码协议头
int body_length = byte_buffer->size()-header_length;
char *header_buffer = byte_buffer->get_data(0, header_length);
header->encode(header_buffer, body_length);
//5. 发送协议
resp_protocol->attach_raw_data(byte_buffer);
send_protocol(socket_handle, resp_protocol);
}
else
{
SLOG_ERROR("can't open file=%s", file_name.c_str());
}
break;
}
default:
SLOG_WARN("receive undefine protocol. ignore it.");
return false;
}
return true;
}
嗯,到现在我们的下载服务器完成了.收工,洗洗睡了... 哦,忘记还有客户端的代码,顺便提供一下,嘿嘿...