thrift http server

原创
2016/06/19 12:23
阅读数 1.9K

http协议参考文章:http://www.cnblogs.com/li0803/archive/2008/11/03/1324746.html

 

http是tcp交换数据中的一种协议

跟字符串协议、thrift protocol、google protocol buf 这些协议都是建立在tcp之上的,最终都是通过 send / recv 来发送和接收数据的

 

如连接:http://www.cnblogs.com/li0803/archive/2008/11/03/1324746.html

在域名后面的 /li0803/archive/2008/11/03/1324746.html 部分,是属于uri资源部分。

在动态语言(php、ruby、python等等)还未盛行的时候,它表示1324746.html这个静态文件在服务器的web上的路径。

如今却不一定了,绝大可能是由程序动态生成的。

这个可以通过各种语言的开放框架的伪静态功能来实现。使用这类型的url的原因是“静态文件”对搜索引擎友好。

 

又如:

curl -XGET http://localhost:8000/user/1

可以表示查询id为1的用户的信息

 

curl -XDELETE http://localhost:8000/user/1

可以表示删除id为1的用户信息

 

curl -XPOST http://localhost:8000/user/ -d '{

"username" : "zhangys",

"sex" : "man",

"age" : 18,

"phone" : 1234567890

}'

可以表示增加一个用户

 

curl -XPUT http://localhost:8000/user/1 -d '{

"username" : "zhangys",

"sex" : "man",

"age" : 18,

"phone" : 1234567890

}'

可以表示更新id为1的用户的信息

 

当然,以上的CURD操作的URL也可以写成这样:

curl -XGET http://localhost:8000/user/1/_get

curl -XGET http://localhost:8000/user/1/_delete

curl -XPOST http://localhost:8000/user/_create -d '{

"username" : "zhangys",

"sex" : "man",

"age" : 18,

"phone" : 1234567890

}'

curl -XPOST http://localhost:8000/user/1/_update -d '{

"username" : "zhangys",

"sex" : "man",

"age" : 18,

"phone" : 1234567890

}'

 

还可以这样:

curl -XPOST http://localhost:8000 -d '{

"cmd" : "get",

"resource" : "user",

"data" : {

"id" : 1

}

}'

curl -XPOST http://localhost:8000 -d '{

"cmd" : "delete",

"resource" : "user",

"data" : {

"id" : 1

}

}'

curl -XPOST http://localhost:8000 -d '{

"cmd" : "create",

"resource" : "user",

"data" : {

"username" : "zhangys",

"sex" : "man",

"age" : 18,

"phone" : 1234567890

}

}'

curl -XPOST http://localhost:8000 -d '{

"cmd" : "update",

"resource" : "user",

"data" : {

"id" : 1,

"username" : "zhangys",

"sex" : "man",

"age" : 18,

"phone" : 1234567890

}

}'

 

灵活运用http的资源操作方法(get/delete/post/put/head等)和url,可以搭配各种各样的协议,如restful

 

=====================================================================================================================================

在后台开发中一般比较少用到http协议,但是http+json更具通用性和灵活性。下面介绍如何用thrift开发一个http服务器

 

 

第一步:编写协议文件 http.thrift

内容:

service HttpService {

}

如上,没有定义任何接口。但是这一步不能少,因为thrift的一些类是定义了却需要你来实现。

 

 

第二步:编译协议文件

thrift -r --gen cpp:cob_style=1 http.thrift

 

 

第三步:编写http.cc代码

=====================================================================================================================================

#include <iostream>

#include <sstream>

#include <string>

#include <signal.h>

 

#include <gflags/gflags.h>

#include <glog/logging.h>

#include <boost/property_tree/ptree.hpp>

#include <boost/property_tree/json_parser.hpp>

 

#include <thrift/async/TAsyncBufferProcessor.h>

#include <thrift/async/TEvhttpServer.h>

 

 

#include "gen-cpp/HttpService.h"

 

using namespace ::apache::thrift;

using namespace ::apache::thrift::async;

 

using boost::shared_ptr;

using namespace boost::property_tree;

 

DEFINE_int32(port, 9090, "");

 

 

class HttpServiceHandler : virtual public HttpServiceIf {

public:

HttpServiceHandler() {

}

 

~HttpServiceHandler() {

}

};

 

 

class HttpProcessor : virtual public TAsyncBufferProcessor {

public:

HttpProcessor() {

// Your initialization goes here

}

 

~HttpProcessor() {

}

 

void process(apache::thrift::stdcxx::function<void(bool healthy)> _return,

boost::shared_ptr<apache::thrift::transport::TBufferBase> ibuf,

boost::shared_ptr<apache::thrift::transport::TBufferBase> obuf) {

 

uint32_t len = 1000;

uint8_t* buf = new uint8_t[len + 1];

memset(buf, 0, len + 1);

 

uint32_t nrd = ibuf->read(buf, len);

buf[nrd] = 0x0;

LOG(INFO) << "recv: " << buf; // 记录接收数据

 

ptree request;

ptree response;

std::stringstream iss;

iss << buf;

 

try {

read_json(iss, request);

response.put<int>("error", 0);

response.put("success", "true");

response.put("message", "");

response.put("data", buf);

} catch(ptree_error& e) {

std::cout << "ptree_error: " << e.what() << std::endl;

response.put<int>("error", -1);

response.put("success", "false");

response.put("message", e.what());

LOG(ERROR) << e.what(); // 记录错误信息

}

 

std::ostringstream oss;

write_json(oss, response);

std::string out = oss.str();

obuf->write((uint8_t *)out.c_str(), out.length());

 

delete buf;

buf = NULL;

_return(true); // _return(false); // 非 200 成功返回码返回

}

 

};

 

 

void processSignal(int signo) {

std::cout << "Signal is " << signo << std::endl;

}

 

 

int main(int argc, char **argv) {

FLAGS_max_log_size = 200;

FLAGS_logbuflevel = 0;

google::ParseCommandLineFlags(&argc, &argv, true);

google::InitGoogleLogging(argv[0]);

 

// signal(SIGINT, processSignal);

signal(SIGTERM, processSignal);

signal(SIGPIPE, processSignal);

 

boost::shared_ptr<TAsyncBufferProcessor> processor(new HttpProcessor);

 

TEvhttpServer server(processor, FLAGS_port);

server.serve();

 

return 0;

}

 

=====================================================================================================================================

其中用到了 boost 的 json 模块,google 的 gflags和glog 模块在接收命令行参数和记录日志。

 

 

第四步:编译源码

g++ -o httpd httpd.cc gen-cpp/http_types.cpp gen-cpp/http_constants.cpp gen-cpp/HttpService.cpp -lthrift -lthriftnb -levent -lboost_system -lboost_thread -lgflags -lglog

 

第五步:运行

./httpd --port=8080 --log_dir=./logs

 

第六步:测试

1、提交正确的数据

zhangys@zhangys :/data/test$ curl -XPOST http://localhost:8080 -d '{"a":"b"}'

{

"error": "0",

"success": "true",

"message": "",

"data": "{\"a\":\"b\"}"

}

2、提交错误的数据

zhangys@zhangys :/data/test$ curl -XPOST http://localhost:8080 -d '111'

{

"error": "-1",

"success": "false",

"message": "<unspecified file>(1): expected object or array"

}

zhangys@zhangys :/data/test$

 

 

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部