Windows+Qt使用gRPC


上篇文章《Windows+VS2017使用gRPC》编译出了Windows下可用的gRPC静态lib库文件,在此基础上要想在Qt上使用,需要使用MSVC2017 64bit构建组件进行构建。

grpc-server

新建基于Widget的Qt工程grpc-server

Widget.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
 
#ifndef  WIDGET_H
#define  WIDGET_H

#include  <QWidget>

#include  <iostream>
#include  <memory>
#include  <string>

#include  <grpcpp/grpcpp.h>

#include   "../grpcSetting/helloworld.grpc.pb.h"

using  grpc::Server;
using  grpc::ServerBuilder;
using  grpc::ServerContext;
using  grpc::Status;
using  helloworld::HelloRequest;
using  helloworld::HelloReply;
using  helloworld::Greeter;

// Logic and data behind the server's behavior.
class  GreeterServiceImpl final :  public  Greeter::Service
{
    Status SayHello(ServerContext *context, 
const  HelloRequest *request,
                    HelloReply *reply) override
    {
        std::string prefix(
"Hello " );
        reply->set_message(prefix + request->name());
        
return  Status::OK;
    }
};

class  QTextBrowser;
class  Widget :  public  QWidget
{
    Q_OBJECT

public :
    Widget(QWidget *parent = nullptr);
    ~Widget();

private  slots:
    
void  startServer();

private :
    QTextBrowser *text;
};

#endif   // WIDGET_H

 

Widget.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
 
#include   "Widget.h"
#include  <QVBoxLayout>
#include  <QTextBrowser>
#include  <QPushButton>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , text(
new  QTextBrowser())
{
    setWindowTitle(tr(
"grpc-server" ));
    resize(
320 460 );

    QVBoxLayout *layout = 
new  QVBoxLayout( this );
    QPushButton *button = 
new  QPushButton( "Start" );
    connect(button, &QPushButton::clicked, 
this , &Widget::startServer);
    layout->addWidget(text);
    layout->addWidget(button);
    setLayout(layout);
}

Widget::~Widget()
{

}

void  Widget::startServer()
{
    std::string server_address(
"0.0.0.0:50051" );
    GreeterServiceImpl service;

    ServerBuilder builder;
    
// Listen on the given address without any authentication mechanism.
    builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
    
// Register "service" as the instance through which we'll communicate with
     // clients. In this case it corresponds to an *synchronous* service.
    builder.RegisterService(&service);
    
// Finally assemble the server.
    std::unique_ptr<Server> server(builder.BuildAndStart());
    std::cout << 
"Server listening on "  << server_address << std::endl;
    
if  (text != nullptr)
    {
        text->setText(QString(tr(
"Server listening on %1" )).arg(server_address.c_str()));
    }

    
// Wait for the server to shutdown. Note that some other thread must be
     // responsible for shutting down the server for this call to ever return.
    server->Wait();
}

grpc-client

新建基于Widget的Qt工程grpc-client

 

Widget.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
 
#ifndef  WIDGET_H
#define  WIDGET_H

#include  <QWidget>

#include  <iostream>
#include  <memory>
#include  <string>

#include  <grpcpp/grpcpp.h>

#include   "../grpcSetting/helloworld.grpc.pb.h"

using  grpc::Channel;
using  grpc::ClientContext;
using  grpc::Status;
using  helloworld::HelloRequest;
using  helloworld::HelloReply;
using  helloworld::Greeter;

class  GreeterClient
{
public :
    GreeterClient(std::shared_ptr<Channel> channel)
        : stub_(Greeter::NewStub(channel)) {}

    
// Assembles the client's payload, sends it and presents the response back
     // from the server.
    std::string SayHello( const  std::string &user)
    {
        
// Data we are sending to the server.
        HelloRequest request;
        request.set_name(user);

        
// Container for the data we expect from the server.
        HelloReply reply;

        
// Context for the client. It could be used to convey extra information to
         // the server and/or tweak certain RPC behaviors.
        ClientContext context;

        
// The actual RPC.
        Status status = stub_->SayHello(&context, request, &reply);

        
// Act upon its status.
         if  (status.ok())
        {
            
return  reply.message();
        }
        
else
        {
            std::cout << status.error_code() << 
": "  << status.error_message()
                      << std::endl;
            
return   "RPC failed" ;
        }
    }

private :
    std::unique_ptr<Greeter::Stub> stub_;
};

class  QTextBrowser;
class  Widget :  public  QWidget
{
    Q_OBJECT

public :
    Widget(QWidget *parent = nullptr);
    ~Widget();

private  slots:
    
void  req();

private :
    QTextBrowser *text;
};

#endif   // WIDGET_H

 

Widget.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 
#include   "Widget.h"
#include  <QVBoxLayout>
#include  <QTextBrowser>
#include  <QPushButton>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , text(
new  QTextBrowser())
{
    setWindowTitle(tr(
"grpc-client" ));
    resize(
320 460 );

    QVBoxLayout *layout = 
new  QVBoxLayout( this );
    QPushButton *button = 
new  QPushButton( "req" );
    connect(button, &QPushButton::clicked, 
this , &Widget::req);
    layout->addWidget(text);
    layout->addWidget(button);
    setLayout(layout);
}

Widget::~Widget()
{

}

void  Widget::req()
{
    
// Instantiate the client. It requires a channel, out of which the actual RPCs
     // are created. This channel models a connection to an endpoint (in this case,
     // localhost at port 50051). We indicate that the channel isn't authenticated
     // (use of InsecureChannelCredentials()).
    GreeterClient greeter(grpc::CreateChannel(
                              
"localhost:50051" , grpc::InsecureChannelCredentials()));
    std::string user(
"world" );
    std::string reply = greeter.SayHello(user);
    std::cout << 
"Greeter received: "  << reply << std::endl;
    
if  (text != nullptr)
    {
        text->setText(QString(
"Greeter received: %1" ).arg(reply.c_str()));
    }

}

Pro文件设置

添加预处理器定义:DEFINES += _WIN32_WINNT=0x0A00

添加链接库以及包含库:这里直接复制过来了,一些冗余的内容可根据实际情况调整

 

*.pro
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
 
INCLUDEPATH += $$PWD/../../../grpc_plugs/grpc/include
INCLUDEPATH += $$PWD/../../../grpc_plugs/grpc/third_party/protobuf/src
DEPENDPATH += $$PWD/../../../grpc_plugs/grpc/include


win32: LIBS += -L$$PWD/../../../grpc_plugs/grpc/.build/Debug/ -lgrpc++
win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../grpc_plugs/grpc/.build/Debug/grpc++.lib
else :win32-g++: PRE_TARGETDEPS += $$PWD/../../../grpc_plugs/grpc/.build/Debug/libgrpc++.a

win32: LIBS += -L$$PWD/../../../grpc_plugs/grpc/.build/Debug/ -lgrpc
win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../grpc_plugs/grpc/.build/Debug/grpc.lib
else :win32-g++: PRE_TARGETDEPS += $$PWD/../../../grpc_plugs/grpc/.build/Debug/libgrpc.a

win32: LIBS += -L$$PWD/../../../grpc_plugs/grpc/.build/Debug/ -lgpr
win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../grpc_plugs/grpc/.build/Debug/gpr.lib
else :win32-g++: PRE_TARGETDEPS += $$PWD/../../../grpc_plugs/grpc/.build/Debug/libgpr.a

win32: LIBS += -L$$PWD/../../../grpc_plugs/grpc/.build/Debug/ -laddress_sorting
win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../grpc_plugs/grpc/.build/Debug/address_sorting.lib
else :win32-g++: PRE_TARGETDEPS += $$PWD/../../../grpc_plugs/grpc/.build/Debug/libaddress_sorting.a

win32: LIBS += -L$$PWD/../../../grpc_plugs/grpc/.build/third_party/protobuf/Debug -llibprotobufd
win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../grpc_plugs/grpc/.build/third_party/protobuf/Debug/libprotobufd.lib
else :win32-g++: PRE_TARGETDEPS += $$PWD/../../../grpc_plugs/grpc/.build/third_party/protobuf/Debug/liblibprotobufd.a

win32: LIBS += -L$$PWD/../../../grpc_plugs/grpc/.build/third_party/zlib/Debug -lzlibd
win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../grpc_plugs/grpc/.build/third_party/zlib/Debug/zlibd.lib
else :win32-g++: PRE_TARGETDEPS += $$PWD/../../../grpc_plugs/grpc/.build/third_party/zlib/Debug/libzlibd.a

win32: LIBS += -L
'C:/Program Files (x86)/Windows Kits/10/Lib/10.0.17763.0/um/x64/'  -lWS2_32

INCLUDEPATH += 
'C:/Program Files (x86)/Windows Kits/10/Lib/10.0.17763.0/um/x64'
DEPENDPATH += 
'C:/Program Files (x86)/Windows Kits/10/Lib/10.0.17763.0/um/x64'

win32:!win32-g++: PRE_TARGETDEPS += 
'C:/Program Files (x86)/Windows Kits/10/Lib/10.0.17763.0/um/x64/WS2_32.lib'
else :win32-g++: PRE_TARGETDEPS +=  'C:/Program Files (x86)/Windows Kits/10/Lib/10.0.17763.0/um/x64/libWS2_32.a'

win32: LIBS += -L
'C:/Program Files (x86)/Windows Kits/10/Lib/10.0.17763.0/um/x64/'  -lAdvapi32

INCLUDEPATH += 
'C:/Program Files (x86)/Windows Kits/10/Lib/10.0.17763.0/um/x64'
DEPENDPATH += 
'C:/Program Files (x86)/Windows Kits/10/Lib/10.0.17763.0/um/x64'

win32:!win32-g++: PRE_TARGETDEPS += 
'C:/Program Files (x86)/Windows Kits/10/Lib/10.0.17763.0/um/x64/Advapi32.lib'
else :win32-g++: PRE_TARGETDEPS +=  'C:/Program Files (x86)/Windows Kits/10/Lib/10.0.17763.0/um/x64/libAdvapi32.a'

win32: LIBS += -L$$PWD/../../../grpc_plugs/grpc/.build/third_party/cares/cares/lib/Debug/ -lcares

INCLUDEPATH += $$PWD/../../../grpc_plugs/grpc/.build/third_party/cares/cares/lib/Debug
DEPENDPATH += $$PWD/../../../grpc_plugs/grpc/.build/third_party/cares/cares/lib/Debug

win32:!win32-g++: PRE_TARGETDEPS += $$PWD/../../../grpc_plugs/grpc/.build/third_party/cares/cares/lib/Debug/cares.lib
else :win32-g++: PRE_TARGETDEPS += $$PWD/../../../grpc_plugs/grpc/.build/third_party/cares/cares/lib/Debug/libcares.a

运行

参考

附录

MinGW使用VS生成的静态库lib文件时,编译不能通过,会提示:
error: No rule to make target '*.a', needed by '*.exe'. Stop.
可见它需要的时*.a的静态库文件,而无法使用*.lib的静态库文件。
但是,MinGW调用linux生成的静态库.a文件,无法链接成功,也无法使用。
网上流传着这样的资料:
首先,下载安装MSYS2:http://www.msys2.org/
(Download and run the installer - "x86_64" for 64-bit, "i686" for 32-bit Windows)
一路“下一步”就可以安装好MSYS2.
然后运行msys2.exe脚本,执行如下命令:
1、pacman -Syu
2、执行完后,关闭终端,重新打开终端执行:pacman -Su
3、pacman -S git
4、pacman -S mingw-w64-i686-grpc
5、pacman -S mingw-w64-i686-qt5
6、pacman -S mingw-w64-i686-qt-creator
之后就可以在安装的qt creator中添加在msys2/mingw32/lib中的grpc静态库和protobuf静态库!!!然后自己根据官网编写简单的C++工程进行测试,只要你库添加的没问题,测试可以通过。
但是,这个叫MSYS2的类Unix环境安装软件很慢,经常出现安装不成功的问题,很不好使!


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM