Windows+Qt使用gRPC

上篇文章《Windows+VS2017使用gRPC》編譯出了Windows下可用的gRPC靜態lib庫文件,在此基礎上要想在Qt上使用,須要使用MSVC2017 64bit構建組件進行構建。html

grpc-server

新建基於Widget的Qt工程grpc-serverlinux

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-clientios

 

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=0x0A00c++

添加連接庫以及包含庫:這裏直接複製過來了,一些冗餘的內容可根據實際狀況調整git

 

*.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腳本,執行以下命令:
一、pacman -Syu
二、執行完後,關閉終端,從新打開終端執行:pacman -Su
三、pacman -S git
四、pacman -S mingw-w64-i686-grpc
五、pacman -S mingw-w64-i686-qt5
六、pacman -S mingw-w64-i686-qt-creator
以後就能夠在安裝的qt creator中添加在msys2/mingw32/lib中的grpc靜態庫和protobuf靜態庫!!!而後本身根據官網編寫簡單的C++工程進行測試,只要你庫添加的沒問題,測試能夠經過。
可是,這個叫MSYS2的類Unix環境安裝軟件很慢,常常出現安裝不成功的問題,很很差使!github

相關文章
相關標籤/搜索