LinuxでC++サーバを作成(HTTPサーバ)
95599 ワード
今日はMakefileを使ってHTTPのサーバーを書きますが、これまでMakefileに触れたことがないので、探ってみる必要があります.
VS 2015でMakefileをテストHTTPTestという名前のMakefile Project(Linux)を新規作成します. 新規項目の追加、C++ファイルの追加(.cpp)、main.cppという名前、内容は以下の通りです: main.cppの同級ディレクトリの下にMakefileの空のファイルを作成し、ファイル名の大文字と小文字に注意し、HTTPTestプロジェクトに追加します.は次のように書き込まれます. 右クリック項目、属性を選択し、GeneralのRemote Build Root DirectoryにLinux上の項目ディレクトリを書き込み、Remote Buildの4項目にそれぞれ を書き込む
図:main.cppの1行にブレークポイントを打ち、F 5を押してデバッグし、テストに成功しました.
libeventのインストール
HTTPサーバlibeventライブラリ実装を選択しました.libeventをLinux仮想マシンにダウンロードし、ここで2.1を選択する.10バージョン、ダウンロード完了後に圧縮パッケージを解凍する
解凍されたフォルダに入りmakefileを生成するコマンドを入力します.-prefixはlibeventのインストールディレクトリを指定します.
入力makeコンパイル; make installを入力してインストールを開始し、インストールに成功すると、/usr/libeventはbin,include,libフォルダを生成します.
環境の設定上記で生成した/usr/libevent/includeをwindowsにコピーする必要があります.ここでは共有フォルダを使用します.
WindowsにE:LinuxSharelibeventincludeディレクトリが表示されました.必要なヘッダファイルです.右クリック項目->プロパティ->C+->Include Search Path、E:LinuxShareinclude;E:\LinuxShare\include\c++\4.8.2;E:\LinuxShare\libevent\include;,前の2つは前のLinuxヘッダファイルで、最後の1つはlibeventヘッダファイルです.
Makefileファイルのbuildは修正が必要です
F 5を押すとコンパイルは通過するが、実行できず、エラーは以下の通りである:error while loading shared libraries:libevent-2.1.so.6:cannot open shared object file:No such file or directory、このライブラリが見つからないことをヒントに、linux端末で入力する方法を解決します
これにより、実行時にライブラリをリンクできます.
パッケージHTTP
myhttpserverを作成します.hとmyhttpserver.cppは,libeventを参照してhttp serverを実現し,多くのバグを経験した後,getとpost法を実現した.
myhttpserver.h
myhttpserver.cpp
main.cpp
Makefileのgccはg++に変更する必要があります.そうしないと、includeとlibがコンパイルして実行できるという問題が発生します. Makefile
ディスプレイの実行
サービス側のHTTPTestにはこれらのファイルがあります. index.htmlの内容は以下の通りです.
トップページ一般ファイルは、ビデオを取得するにはhtmlに接続を書き込む必要があることを示しており、画像、gifのように直接開くことはできません.そうしないと、ダウンロードインタフェースから飛び出します.indexページ送信ボタンをクリックbyeサーバを閉じる
VS 2015でMakefileをテスト
#pragma once
#pragma execution_character_set("utf-8")
#include
int main()
{
printf("HttpServer
");
int count = 0;
while (count<3)
{
count++;
printf("hello %d
",count);
}
printf("HttpServer
");
return 0;
}
build:
gcc -gdwarf-2 -o HTTPTest main.cpp
clean:
rm -rf HTTPTest
cd $(RemoteRootDir)/$(ProjectName); make build
cd $(RemoteRootDir)/$(ProjectName); make clean build
cd $(RemoteRootDir)/$(ProjectName); make clean
$(RemoteRootDir)/$(ProjectName)/HTTPTest
図:
libeventのインストール
HTTPサーバlibeventライブラリ実装を選択しました.
tar xvf libevent-2.1.10-stable.tar.gz
cd libevent-2.1.10-stable/
./configure --prefix=/usr/libevent
環境の設定
mkdir /mnt/hgfs/LinuxShare/libevent
cp -r /usr/libevent/include /mnt/hgfs/LinuxShare/libevent
WindowsにE:LinuxSharelibeventincludeディレクトリが表示されました.必要なヘッダファイルです.
Makefileファイルのbuildは修正が必要です
gcc -gdwarf-2 -o HTTPTest main.cpp -I /usr/libevent/include/ -L /usr/libevent/lib/ -levent
F 5を押すとコンパイルは通過するが、実行できず、エラーは以下の通りである:error while loading shared libraries:libevent-2.1.so.6:cannot open shared object file:No such file or directory、このライブラリが見つからないことをヒントに、linux端末で入力する方法を解決します
ln -s /usr/libevent/lib/libevent-2.1.so.6 /usr/lib64/libevent-2.1.so.6
これにより、実行時にライブラリをリンクできます.
パッケージHTTP
myhttpserverを作成します.hとmyhttpserver.cppは,libeventを参照してhttp serverを実現し,多くのバグを経験した後,getとpost法を実現した.
myhttpserver.h
#pragma once
#include
#include
#include
static bool closesign = false;
// Content-Type
const char *get_file_type(char *name);
// html
int send_dir(struct evbuffer* bev, const char *dirname);
//http
int send_header(struct evhttp_request* request, const char* filename, long filelen, const char* connest);
//
int send_file_to_http(const char *filename, struct evbuffer* bev);
//
void HttpGenericCallback(struct evhttp_request* request, void* arg);
class Myhttpserver
{
public:
Myhttpserver();
~Myhttpserver();
private:
struct event_base* base;
struct evhttp* http;
char errmsg[512];
public:
//
bool inithttp();
//
bool start(unsigned int port);
//
void set_gencb(void(*cb)(struct evhttp_request *, void *));
//
void dispatch();
static void stop(struct event_base* base);
void free();
char* geterrmsg();
};
myhttpserver.cpp
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "myhttpserver.h"
/*
charset=iso-8859-1 , ;
charset=gb2312 ;
charset=utf-8 ;
、 、
charset=euc-kr ;
charset=big5 ;
,
http
*/
const char *get_file_type(const char *name) {
char* dot;
char tmpname[128] = {0};
strncpy(tmpname, name, strlen(name));
dot = strrchr(tmpname, '.'); // ‘.’ ; NULL
if (dot == (char*)0)
return "text/plain; charset=utf-8";
if (strcmp(dot, ".html") == 0 || strcmp(dot, ".htm") == 0)
return "text/html; charset=utf-8";
if (strcmp(dot, ".jpg") == 0 || strcmp(dot, ".jpeg") == 0)
return "image/jpeg";
if (strcmp(dot, ".gif") == 0)
return "image/gif";
if (strcmp(dot, ".png") == 0)
return "image/png";
if (strcmp(dot, ".css") == 0)
return "text/css";
if (strcmp(dot, ".au") == 0)
return "audio/basic";
if (strcmp(dot, ".wav") == 0)
return "audio/wav";
if (strcmp(dot, ".avi") == 0)
return "video/x-msvideo";
if (strcmp(dot, ".mov") == 0 || strcmp(dot, ".qt") == 0)
return "video/quicktime";
if (strcmp(dot, ".mpeg") == 0 || strcmp(dot, ".mpe") == 0)
return "video/mpeg";
if (strcmp(dot, ".vrml") == 0 || strcmp(dot, ".wrl") == 0)
return "model/vrml";
if (strcmp(dot, ".midi") == 0 || strcmp(dot, ".mid") == 0)
return "audio/midi";
if (strcmp(dot, ".mp3") == 0)
return "audio/mpeg";
if (strcmp(dot, ".ogg") == 0)
return "application/ogg";
if (strcmp(dot, ".pac") == 0)
return "application/x-ns-proxy-autoconfig";
return "text/plain; charset=utf-8";
}
int send_header(struct evhttp_request* request, const char* filename, long filelen, const char* connest) {
//
evhttp_add_header(request->output_headers, "Content-Type", get_file_type(filename));
//
if (filelen > 0)
{
char charsize[50] = { 0 };
sprintf(charsize, "%ld", filelen);
evhttp_add_header(request->output_headers, "Content-Length", charsize);
}
// Connection: close/keep-alive
evhttp_add_header(request->output_headers, "Connection", connest);
return 0;
}
int send_dir(struct evbuffer* bev, const char *dirname) {
char encoded_name[1024];
char path[1024];
char timestr[64];
struct stat sb;
struct dirent **dirinfo;
char buf[4096] = { 0 };
sprintf(buf, "%s ", dirname);
sprintf(buf + strlen(buf), " :%s", dirname);// int num =scandir(dirname,&dirinfo,NULL, alphasort);for(int i =0; i<num;++i){// strcpy(encoded_name, dirinfo[i]->d_name);sprintf(path,"%s%s", dirname, dirinfo[i]->d_name);printf("############# path = %s
", path);if(lstat(path,&sb)<0){sprintf(buf +strlen(buf),"
",
encoded_name, dirinfo[i]->d_name);}else{strftime(timestr,sizeof(timestr)," %d %b %Y %H:%M",localtime(&sb.st_mtime));if(S_ISDIR(sb.st_mode)){sprintf(buf +strlen(buf),"
",
encoded_name, dirinfo[i]->d_name, timestr, sb.st_size);}else{sprintf(buf +strlen(buf),"
",
encoded_name, dirinfo[i]->d_name, timestr, sb.st_size);}}//bufferevent_write(bev, buf, strlen(buf));evbuffer_add_printf(bev, buf);printf(buf);memset(buf,0,sizeof(buf));}sprintf(buf +strlen(buf),"
%s
%s/ %s %ld
%s %s %ld
");
//bufferevent_write(bev, buf, strlen(buf));
evbuffer_add_printf(bev, buf);
printf(buf);
printf("################# Dir Read OK !!!!!!!!!!!!!!
");
return 0;
}
int send_file_to_http(const char *filename, struct evbuffer* bev) {
int fd = open(filename, O_RDONLY);
int ret = 0;
char buf[4096] = { 0 };
// 4096
//evbuffer_read(bev, fd, 30556);
while ((ret = read(fd, buf, sizeof(buf)))) {
if (ret < 0)
break;
// \0
//evbuffer_add_printf(bev, buf);
// \0
evbuffer_add(bev, buf, ret);
memset(buf, 0, 4096);
}
close(fd);
return 0;
}
//
void HttpGenericCallback(struct evhttp_request* request, void* arg)
{
const struct evhttp_uri* evhttp_uri = evhttp_request_get_evhttp_uri(request);
char url[8192];
memset(url, 0x00, sizeof(url));
evhttp_uri_join(const_cast<struct evhttp_uri*>(evhttp_uri), url, 8192);
printf("accept request url:%s
", url);
if (request->kind == EVHTTP_REQUEST) {
//get
if (request->type == EVHTTP_REQ_GET) {
/*
http://foo.com/?q=test&s=some+thing
evhttp_request_uri: HTTP ur, /?q=test&s=some+thing
evhttp_parse_query: , evkeyvalq , key/value .
*/
char* decode_uri = strdup((char*)evhttp_request_uri(request));
struct evkeyvalq http_query;
evhttp_parse_query(decode_uri, &http_query);
free(decode_uri);
//const char *request_value = evhttp_find_header(&http_query, "data");
//
//strcpy(url, evhttp_decode_uri(url));
char *pf = &url[1];
if (strcmp(url, "/") == 0 || strcmp(url, "/.") == 0) {
pf = "./";
}
printf("***** http Request Resource Path = %s, pf = %s
", url, pf);
//
if (strcmp(url, "/bye") == 0) {
closesign = true;
struct event_base* base = (struct event_base*)arg;
Myhttpserver::stop(base);
return;
}
struct stat sb;
struct evbuffer* evbuf = evbuffer_new();
if (!evbuf) {
printf("create evbuffer failed!
");
return;
}
char dir[256] = { 0 }, filename[256] = { 0 };
snprintf(dir, sizeof(dir), "/home/aubin/projects/HTTPTest/%s", pf);
//
if (stat(dir, &sb) == 0 && (sb.st_mode & S_IFREG)) {
send_header(request, pf, sb.st_size, "close");
send_file_to_http(dir, evbuf);
evhttp_send_reply(request, HTTP_OK, "OK", evbuf);
evbuffer_free(evbuf);
return;
}
//
else if (stat(dir, &sb) == 0 && (sb.st_mode & __S_IFDIR)) {
send_header(request, ".html", 0, "close");
send_dir(evbuf, dir);
evhttp_send_reply(request, HTTP_OK, "OK", evbuf);
evhttp_clear_headers(&http_query);
evbuffer_free(evbuf);
return;
}
//
else {
send_header(request, ".html", 0, "close");
send_dir(evbuf, "/home/aubin/projects/HTTPTest");
evhttp_send_reply(request, HTTP_OK, "OK", evbuf);
evhttp_clear_headers(&http_query);
evbuffer_free(evbuf);
return;
}
}
//post
else if (request->type == EVHTTP_REQ_POST) {
char charadd1[10], charadd2[10];
struct evkeyvalq http_query_post;
char decode_post_uri[1024] = { 0 };
int buffer_data_len = EVBUFFER_LENGTH(request->input_buffer);
char *post_data = (char *)malloc(buffer_data_len + 1);
memset(post_data, 0, buffer_data_len + 1);
memcpy(post_data, EVBUFFER_DATA(request->input_buffer), buffer_data_len);
sprintf(decode_post_uri, "/?%s", post_data); //
evhttp_parse_query(decode_post_uri, &http_query_post);
strcpy(charadd1, evhttp_find_header(&http_query_post, "add1"));
strcpy(charadd2, evhttp_find_header(&http_query_post, "add2"));
int sum = atoi(charadd1) + atoi(charadd2);
struct evbuffer* evbuf = evbuffer_new();
if (!evbuf) {
printf("create evbuffer failed!
");
return;
}
evbuffer_add_printf(evbuf, "\
\
\
\
(runoob.com) \
\
\
%d
\
\
", sum);
evhttp_send_reply(request, HTTP_OK, "OK", evbuf);
evbuffer_free(evbuf);
}
}
}
Myhttpserver::Myhttpserver()
{
}
Myhttpserver::~Myhttpserver()
{
}
bool Myhttpserver::inithttp()
{
event_init();
base = event_base_new();
if (!base)
{
sprintf(errmsg, "create event_base failed,error: %s(errno: %d)
", strerror(errno), errno);
return false;
}
http = evhttp_new(base);
if (!http)
{
sprintf(errmsg, "create evhttp failed,error: %s(errno: %d)
", strerror(errno), errno);
return false;
}
return true;
}
bool Myhttpserver::start(unsigned int port)
{
if (evhttp_bind_socket(http, "0.0.0.0", port) != 0)
{
sprintf(errmsg, "start evhttp failed,error: %s(errno: %d)
", strerror(errno), errno);
return false;
}
evhttp_set_timeout(http, 120);
return true;
}
void Myhttpserver::set_gencb(void(*cb)(struct evhttp_request *, void *))
{
evhttp_set_gencb(http, cb, base);
}
void Myhttpserver::dispatch()
{
event_base_dispatch(base);
}
void Myhttpserver::stop(struct event_base* base)
{
event_base_loopbreak(base);
event_base_loopexit(base, 0);
return;
}
void Myhttpserver::free()
{
evhttp_free(http);
event_base_free(base);
}
char * Myhttpserver::geterrmsg()
{
return errmsg;
}
main.cpp
#pragma once
#pragma execution_character_set("utf-8")
#include
#include
#include
#include
#include
#include
#include "myhttpserver.h"
int main(int argc, char **argv) {
Myhttpserver httpserver;
if (!httpserver.inithttp()) {
printf(httpserver.geterrmsg());
return 1;
}
if (!httpserver.start(5000))
{
printf(httpserver.geterrmsg());
return 1;
}
httpserver.set_gencb(HttpGenericCallback);
httpserver.dispatch();
httpserver.free();
return 0;
}
Makefileのgccはg++に変更する必要があります.そうしないと、includeとlibがコンパイルして実行できるという問題が発生します. Makefile
INCLUDEPATH=/usr/libevent/include
LIBPATH=/usr/libevent/lib
CC1=g++
build:main.o myhttpserver.o
$(CC1) -gdwarf-2 -o HTTPTest main.o myhttpserver.o -I $(INCLUDEPATH) -L $(LIBPATH) -levent
main.o:main.cpp myhttpserver.h
$(CC1) -gdwarf-2 -c main.cpp -I $(INCLUDEPATH) -L $(LIBPATH) -levent
myhttpserver.o:myhttpserver.cpp myhttpserver.h
$(CC1) -gdwarf-2 -c myhttpserver.cpp -I $(INCLUDEPATH) -L $(LIBPATH) -levent
clean:
rm *.o HTTPTest
ディスプレイの実行
サービス側のHTTPTestにはこれらのファイルがあります. index.htmlの内容は以下の通りです.
<html>
<head>
<meta charset="utf-8">
<title> (runoob.com)title>
head>
<body>
<form name="input" action="/add" method="post">
add1: <input type="text" name="add1">
add2: <input type="text" name="add2">
<input type="submit" value="Submit">
form>
<p><b> :b> 。 20 。p>
body>
html>
トップページ一般ファイルは、ビデオを取得するにはhtmlに接続を書き込む必要があることを示しており、画像、gifのように直接開くことはできません.そうしないと、ダウンロードインタフェースから飛び出します.indexページ送信ボタンをクリックbyeサーバを閉じる