Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7f21db4

Browse files
committed
Example File Server with async_server and mmap.
This commit implements a file server using the asynchronous file_serverand mmap on Linux. This is a functional file server which serves alldata as 'x-application/octet-stream'. The implementation caches theregion of the mmap for every file accessed through the server.
1 parenta155444 commit7f21db4

File tree

3 files changed

+187
-0
lines changed

3 files changed

+187
-0
lines changed

‎libs/network/example/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@ if (Boost_FOUND)
1515
add_executable(http_clienthttp_client.cpp)
1616
add_executable(simple_wgetsimple_wget.cpp)
1717
add_executable(hello_world_serverhttp/hello_world_server.cpp)
18+
add_executable(fileserverhttp/fileserver.cpp)
1819
add_executable(uriuri.cpp)
1920
target_link_libraries(http_client${Boost_LIBRARIES}${CMAKE_THREAD_LIBS_INIT}${OPENSSL_LIBRARIES} )
2021
target_link_libraries(simple_wget${Boost_LIBRARIES}${CMAKE_THREAD_LIBS_INIT}${OPENSSL_LIBRARIES} )
2122
target_link_libraries(hello_world_server${Boost_LIBRARIES}${CMAKE_THREAD_LIBS_INIT}${OPENSSL_LIBRARIES} )
23+
target_link_libraries(fileserver${Boost_LIBRARIES}${CMAKE_THREAD_LIBS_INIT})
2224
set_target_properties(http_clientPROPERTIESRUNTIME_OUTPUT_DIRECTORY../../../build/example)
2325
set_target_properties(simple_wgetPROPERTIESRUNTIME_OUTPUT_DIRECTORY../../../build/example)
2426
set_target_properties(hello_world_serverPROPERTIESRUNTIME_OUTPUT_DIRECTORY../../../build/example)
27+
set_target_properties(fileserverPROPERTIESRUNTIME_OUTPUT_DIRECTORY../../../build/example)
2528
set_target_properties(uriPROPERTIESRUNTIME_OUTPUT_DIRECTORY../../../build/example)
2629
endif()

‎libs/network/example/Jamfile.v2

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@ exe hello_world_server : http/hello_world_server.cpp ;
3333
exe hello_world_client : http/hello_world_client.cpp ;
3434

3535
exe one_liner : http/one_liner.cpp ;
36+
37+
exe fileserver : http/fileserver.cpp ;
38+
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
// Copyright 2010 Dean Michael Berris.
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// (See accompanying file LICENSE_1_0.txt or copy at
4+
// http://www.boost.org/LICENSE_1_0.txt)
5+
6+
#include<boost/network/include/http/server.hpp>
7+
#include<boost/thread.hpp>
8+
#include<boost/lexical_cast.hpp>
9+
#include<sys/mman.h>
10+
#include<sys/types.h>
11+
#include<sys/stat.h>
12+
#include<sys/fcntl.h>
13+
#include<unistd.h>
14+
#include<iostream>
15+
16+
namespacehttp= boost::network::http;
17+
namespaceutils= boost::network::utils;
18+
19+
structfile_server;
20+
typedef http::async_server<file_server> server;
21+
22+
structfile_cache {
23+
24+
typedef std::map<std::string, std::pair<void*,std::size_t> > region_map;
25+
typedef std::map<std::string, std::vector<server::response_header> > meta_map;
26+
27+
std::string doc_root_;
28+
region_map regions;
29+
meta_map file_headers;
30+
boost::shared_mutex cache_mutex;
31+
32+
explicitfile_cache(std::stringconst & doc_root)
33+
: doc_root_(doc_root) {}
34+
35+
~file_cache()throw () {
36+
BOOST_FOREACH(region_map::value_typeconst & region, regions) {
37+
munmap(region.second.first, region.second.second);
38+
}
39+
}
40+
41+
boolhas(std::stringconst & path) {
42+
boost::shared_lock<boost::shared_mutex>lock(cache_mutex);
43+
return regions.find(doc_root_ + path) != regions.end();
44+
}
45+
46+
booladd(std::stringconst & path) {
47+
boost::upgrade_lock<boost::shared_mutex>lock(cache_mutex);
48+
if (regions.find(doc_root_ + path) != regions.end())returntrue;
49+
std::string real_filename = doc_root_+path;
50+
int fd =open(real_filename.c_str(), O_RDONLY|O_NOATIME|O_NONBLOCK);
51+
if (fd == -1)returnfalse;
52+
std::size_t size =lseek(fd,0, SEEK_END);
53+
void * region =mmap(0, size, PROT_READ, MAP_PRIVATE, fd,0);
54+
if (region == MAP_FAILED) {close(fd);returnfalse; }
55+
56+
boost::upgrade_to_unique_lock<boost::shared_mutex>unique_lock(lock);
57+
regions.insert(std::make_pair(real_filename,std::make_pair(region, size)));
58+
static server::response_header common_headers[] = {
59+
{"Connection","close"}
60+
,{"Content-Type","x-application/octet-stream"}
61+
,{"Content-Length","0"}
62+
};
63+
std::vector<server::response_header>headers(common_headers, common_headers+3);
64+
headers[2].value = boost::lexical_cast<std::string>(size);
65+
file_headers.insert(std::make_pair(real_filename, headers));
66+
returntrue;
67+
}
68+
69+
std::pair<void*,std::size_t>get(std::stringconst & path) {
70+
boost::shared_lock<boost::shared_mutex>lock(cache_mutex);
71+
region_map::const_iterator region = regions.find(doc_root_+path);
72+
if (region != regions.end())return region->second;
73+
elsereturn std::pair<void*,std::size_t>(0,0);
74+
}
75+
76+
boost::iterator_range<std::vector<server::response_header>::iterator>meta(std::stringconst & path) {
77+
boost::shared_lock<boost::shared_mutex>lock(cache_mutex);
78+
static std::vector<server::response_header> empty_vector;
79+
meta_map::iterator headers = file_headers.find(doc_root_+path);
80+
if (headers != file_headers.end()) {
81+
std::vector<server::response_header>::iterator begin = headers->second.begin()
82+
, end = headers->second.end();
83+
returnboost::make_iterator_range(begin,end);
84+
}elsereturnboost::make_iterator_range(empty_vector);
85+
}
86+
87+
};
88+
89+
structconnection_handler : boost::enable_shared_from_this<connection_handler> {
90+
explicitconnection_handler(file_cache & cache)
91+
: file_cache_(cache) {}
92+
93+
voidoperator()(std::stringconst & path, server::connection_ptr connection,bool serve_body) {
94+
bool ok =false;
95+
if (!file_cache_.has(path)) ok = file_cache_.add(path);
96+
if (ok) {
97+
send_headers(file_cache_.meta(path), connection);
98+
if (serve_body)send_file(file_cache_.get(path),0, connection);
99+
}else {
100+
not_found(path, connection);
101+
}
102+
}
103+
104+
voidnot_found(std::stringconst & path, server::connection_ptr connection) {
105+
static server::response_header headers[] = {
106+
{"Connection","close"}
107+
,{"Content-Type","text/plain"}
108+
};
109+
connection->set_status(server::connection::not_found);
110+
connection->set_headers(boost::make_iterator_range(headers, headers+2));
111+
connection->write("File Not Found!");
112+
}
113+
114+
template<classRange>
115+
voidsend_headers(Rangeconst & headers, server::connection_ptr connection) {
116+
connection->set_status(server::connection::ok);
117+
connection->set_headers(headers);
118+
}
119+
120+
voidsend_file(std::pair<void *,std::size_t> mmaped_region,off_t offset, server::connection_ptr connection) {
121+
// chunk it up page by page
122+
std::size_t adjusted_offset = offset+4096;
123+
off_t rightmost_bound =std::min(mmaped_region.second, adjusted_offset);
124+
connection->write(
125+
boost::make_iterator_range(
126+
static_cast<charconst *>(mmaped_region.first) + offset,
127+
static_cast<charconst *>(mmaped_region.first) + rightmost_bound
128+
)
129+
,boost::bind(
130+
&connection_handler::handle_chunk,
131+
connection_handler::shared_from_this(),
132+
mmaped_region,
133+
rightmost_bound,
134+
connection,
135+
_1
136+
)
137+
);
138+
}
139+
140+
voidhandle_chunk(std::pair<void *, std::size_t> mmaped_region,off_t offset, server::connection_ptr connection, boost::system::error_codeconst & ec) {
141+
if (!ec && offset < mmaped_region.second)send_file(mmaped_region, offset, connection);
142+
}
143+
144+
file_cache & file_cache_;
145+
};
146+
147+
structfile_server {
148+
explicitfile_server(file_cache & cache)
149+
: cache_(cache) {}
150+
151+
voidoperator()(
152+
server::requestconst & request,
153+
server::connection_ptr connection
154+
) {
155+
if (request.method =="HEAD") {
156+
boost::shared_ptr<connection_handler>h(newconnection_handler(cache_));
157+
(*h)(request.destination, connection,false);
158+
}elseif (request.method =="GET") {
159+
boost::shared_ptr<connection_handler>h(newconnection_handler(cache_));
160+
(*h)(request.destination, connection,true);
161+
}else {
162+
static server::response_header error_headers[] = {
163+
{"Connection","close" }
164+
};
165+
connection->set_status(server::connection::not_supported);
166+
connection->set_headers(boost::make_iterator_range(error_headers, error_headers+1));
167+
connection->write("Method not supported.");
168+
}
169+
}
170+
171+
file_cache & cache_;
172+
};
173+
174+
intmain(int argc,char * argv[]) {
175+
file_cachecache(".");
176+
file_serverhandler(cache);
177+
utils::thread_poolthread_pool(4);
178+
serverinstance("127.0.0.1","8000", handler, thread_pool);
179+
instance.run();
180+
return0;
181+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp