• thrift在windows的编译/安装--c++版


    前言:
      thrift是出于Facebook的rpc网络编程框架, 其对跨平台和多语言的支持优于google protobuf, 但thrift在java/c#语言上应用比较多, 资料也丰富, 在windows平台的c++这块, 资料相对较少, 而且编译也麻烦. 这篇博客主要记录对thrift在windows上的编译和使用过程, 不涉及原理, 也不具体涉及应用.如有不足, 请各位指正.

    执行过程
    1. 下载并安装Visual Studio
    notice: visual studio 有windows版本限制, 比如visual studio 2013在windows 7就安装不了
    参考网址: http://www.visualstudio.com/zh-cn/visual-studio-2013-compatibility-vs
    系统: windows7 + visual studio 2012

    2. boost安装/编译/链接
      具体步骤如下:
      *) 下载boost
        1. 下载 boost_1_55_0.zip
      *) 编译boost
        1. 执行 bootstrap.bat
        2. 执行 b2.exe (编译的时间较长, 请耐心等待)
      *) 验证boost
        在virtual studio的window console工程属性中添加如下:
        1. 附加包含目录: $BOOST_HOME
        2. 附加库目录: $BOOST_HOMEstagelib
        3. 编写如下代码进行编译/运行认证

     1 #include <iostream>
     2 #include <string>
     3 #include <boost/regex.hpp>
     4 int main()
     5 {
     6  boost::regex pattern("\w+@\w+(\.\w+)*");
     7  std::string mail("xxx@gmail.com");
     8  
     9  if ( boost::regex_match(mail, pattern) ) {
    10   std::cout << mail << " is a valid mail address!" << std::endl;
    11  } else {
    12   std::cout << mail << " is not a valid mail address!" << std::endl;
    13  }
    14 }

      安装boost和配置visual studio的参考网址如下所示:
      http://blog.csdn.net/stanfordzhang/article/details/8587282
      http://www.cnblogs.com/me115/archive/2010/10/08/1845825.html
      http://www.cnblogs.com/chuncn/archive/2012/09/10/2679026.html

    3. libevent的编译/安装/链接
      *) 参考的编译/安装过程网页
      http://blog.s135.com/libevent_windows/
      *) 下载libevent
      http://libevent.org/
      *) 编译libevent
      遇到的编译错误处理方案
      http://10305101ivy.blog.163.com/blog/static/584765892012227322607/

      http://blog.csdn.net/boyxiaolong/article/details/17057063
      evutil.c添加如下行:

     1 #ifdef WIN32
     2 #include <winsock2.h>
     3 #include <ws2tcpip.h>
     4 #pragma comment(lib,"ws2_32.lib") 
     5 #define WIN32_LEAN_AND_MEAN
     6 #include <windows.h>
     7 #undef WIN32_LEAN_AND_MEAN
     8 #include <io.h>
     9 #include <tchar.h>
    10 #endif

      nmake /f Makefile.nmake
      生成libevent_core.lib libevent_extras.lib libevent.lib
      若遇到头文件找不到的问题, 需要手动修改Makefile.nmake文件, 添加相关的头文件路径

    CFLAGS=/IWIN32-Code /Iinclude /Icompat /DWIN32 /DHAVE_CONFIG_H /I. /I"C:Program Files (x86)Windows Kits8.0Includeum" /I"C:Program Files (x86)Windows Kits8.0Includeshared" /I"C:Program Files (x86)Microsoft Visual Studio 11.0VCinclude"
        具体添加的原则是编译缺那个头文件, 就去添加相关的系统头文件目录   
        编写libevent代码编译/运行成功
    1 #include <event.h>
    2 #include <stdio.h>
    3 
    4 int main()
    5 {
    6     const char *version = event_get_version();
    7     printf("%s
    ",version);
    8     return 0;
    9 }
        附加依赖项: ws2_32.lib , libevent_core.lib ,libevent.lib, libevent_extras.lib

    4. thrift的编译/链接
      *)下载thrift 0.9.0源码
      下载网址: http://archive.apache.org/dist/thrift
      *)thrift依赖的库
      http://www.coder4.com/archives/3777
      thrift 依赖 boost库(1.4.7), thriftnb 依赖 boost/libevent库
      http://www.iteye.com/problems/87958
      thrift在编译过程中, 会遇到二义性
      “_wassert”: 对重载函数的调用不明确
      void _wassert(const wchar_t *,const wchar_t *,unsigned int)
      void apache::thrift::protocol::_wassert(const wchar_t *,const wchar_t *,unsigned int)
      解决方案:
      这算命令空间污染的问题, 添加::, 使得对_wassert的调用采用全局声明的那个函数

    1 assert.h
    2  
    3 #define assert(_Expression) (void)( (!!(_Expression)) || (_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) )
    4  
    5 #define assert(_Expression) (void)( (!!(_Expression)) || (::_wassert(_CRT_WIDE(#_Expression), _CRT_WIDE(__FILE__), __LINE__), 0) )
    6      
        测试验证:
        编写 hello.thrift 文件
    1 namespace cpp test
    2  
    3 service HelloService {
    4     string hello(1: string username); 
    5 }
      thrift.exe -gen cpp hello.thrift 
    1 2014/05/07 11:35 9,215 HelloService.cpp
    2 2014/05/07 11:26 7,117 HelloService.h
    3 2014/05/07 11:26 1,422 HelloService_server.skeleton.cpp
    4 2014/05/07 11:35 268 hello_constants.cpp
    5 2014/05/07 11:35 357 hello_constants.h
    6 2014/05/07 11:35 202 hello_types.cpp
    7 2014/05/07 11:35 367 hello_types.h 
        编译执行, 遇到10093错误, 如何去解决?
        WSANOTINITIALISED,  which means WSAStartup() has not been called yet.
        编译完成后运行时会报WSAStartup错误    
        解决方案:
        http://hi.baidu.com/fsx92/item/9f7a96efd33f9f1b585dd88c                  
        编写测试case
      服务端代码:
     1 class HelloServiceHandler : virtual public HelloServiceIf {
     2  public:
     3   HelloServiceHandler() {
     4     // Your initialization goes here
     5   }
     6  
     7   void hello(std::string& _return, const std::string& username) {
     8  _return = "hello " + username;
     9   }
    10  
    11 };
    12  
    13 int main(int argc, char **argv) {
    14   int port = 9090;
    15  
    16   TWinsockSingleton::create();      // 需要用户自己添加, 进行WSAStartup的初始化, 算是windows 版的thrift的一个疏忽
    17  
    18   shared_ptr<HelloServiceHandler> handler(new HelloServiceHandler());
    19   shared_ptr<TProcessor> processor(new HelloServiceProcessor(handler));
    20   shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
    21   shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
    22   shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
    23  
    24   TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
    25   server.serve();
    26   return 0;
    27 }
        客户端代码 
     1  
     2 #include "HelloService.h"
     3 #include <thrift/protocol/TBinaryProtocol.h>
     4 #include <thrift/server/TSimpleServer.h>
     5 #include <thrift/transport/TBufferTransports.h>
     6 #include <thrift/transport/TSocket.h>
     7  
     8 using namespace ::apache::thrift;
     9 using namespace ::apache::thrift::protocol;
    10 using namespace ::apache::thrift::transport;
    11 using namespace ::apache::thrift::server;
    12  
    13 using boost::shared_ptr;
    14  
    15 using namespace ::test;
    16  
    17 int main()
    18 {
    19  
    20  shared_ptr<TTransport> socket(new TSocket("127.0.0.1", 9090));
    21  shared_ptr<TTransport> transport(new TBufferedTransport(socket));
    22  shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
    23  
    24  HelloServiceClient client(protocol);
    25  
    26  try {
    27   transport->open();
    28   std::string res;
    29   client.hello(res, "lilei");
    30   std::cout << res << std::endl;
    31  } catch(TException &e) {
    32   std::cout << e.what() << std::endl;
    33  }
    34  
    35  return 0;
    36 }
    37  
        推荐做法:
        对依赖库的整理, 这是一个好的习惯
        每个库单独创建一个头文件目录, 和库文件目录, 所有的库统一在同一个库仓库下,  c++的库管理不如java的maven那么方便, 又进入一个石器时代, 库的维护需要开发者手动去支持, 但这是种很好的工程实践.     
        
        repository目录为顶级的仓库目录, 以boost为例, boost表示库名, 之下boost/1.55.0为boost的具体的某一版本, 而boost/0.55.0/include为这个版本的头文件目录, boost/0.55.0/lib为这个版本的lib库目录
  • 相关阅读:
    研究下线程投递
    IOCP笔记
    线程同步之mutex和Semaphore
    线程同步之mutex和event区别
    MyStack
    unix环境高级编程 读书笔记
    binary search tree study
    技术博客地址搜集
    select收数据
    奇怪的问题
  • 原文地址:https://www.cnblogs.com/mumuxinfei/p/3715721.html
Copyright © 2020-2023  润新知