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(
320460);

    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(
320460);

    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环境安装软件很慢,经常出现安装不成功的问题,很不好使!

原文地址:https://www.cnblogs.com/MakeView660/p/11512346.html