master
Сергей Маринкевич 2 months ago
parent 7ce411b643
commit 1f16ef6b37

@ -1,48 +1,21 @@
#include "MyService.proxy.h" #include "MyService.proxy.h"
#include "rpc/RpcChannel.h" #include "rpc/IpcPipeChannel.h"
#include <fcntl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h>
#include <iostream> #include <iostream>
#include <string>
class RpcChannelFifoClient : public RpcChannel {
public:
RpcChannelFifoClient(const char* inPipe, const char* outPipe) {
fdOut = open(inPipe, O_WRONLY);
fdIn = open(outPipe, O_RDONLY);
}
void send(const std::string& data) override {
::write(fdOut, data.c_str(), data.size());
::write(fdOut, "\n", 1);
}
std::string receive() override {
char buf[4096];
int n = ::read(fdIn, buf, sizeof(buf) - 1);
if (n <= 0) {
return {};
}
buf[n] = 0;
return std::string(buf);
}
private:
int fdIn{};
int fdOut{};
};
int main() { int main() {
// Создание FIFO — часть пользовательского IPCкода.
mkfifo("/tmp/rpc_in", 0666); mkfifo("/tmp/rpc_in", 0666);
mkfifo("/tmp/rpc_out", 0666); mkfifo("/tmp/rpc_out", 0666);
RpcChannelFifoClient ch("/tmp/rpc_in", "/tmp/rpc_out"); // IPCуровень: канал поверх pipe.
IpcPipeChannel ch("/tmp/rpc_in", "/tmp/rpc_out");
// RPCуровень: прокси поверх канала.
MyServiceProxy proxy(ch); MyServiceProxy proxy(ch);
int r = proxy.add(7, 8); int r = proxy.add(7, 8);
std::cout << "RESULT: " << r << std::endl; std::cout << "RESULT: " << r << std::endl;
} }

@ -0,0 +1,40 @@
#pragma once
#include <sstream>
#include <string>
// Примитивный IPCформат сообщений:
// комбинация std::ostringstream / std::istringstream с удобным API add<T>/read<T>.
class IpcMessageWriter {
public:
template<typename T>
void add(const T& v) {
out_ << v << ' ';
}
std::string str() const {
return out_.str();
}
private:
std::ostringstream out_;
};
class IpcMessageReader {
public:
explicit IpcMessageReader(const std::string& data)
: in_(data) {}
template<typename T>
T read() {
T v{};
in_ >> v;
return v;
}
private:
std::istringstream in_;
};

@ -0,0 +1,57 @@
#pragma once
#include "RpcChannel.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string>
// IPCканал поверх именованных pipe.
// Инкапсулирует работу с файловыми дескрипторами и обмен строковыми сообщениями.
class IpcPipeChannel : public RpcChannel {
public:
IpcPipeChannel(const char* writePipe, const char* readPipe) {
// Канал не создаёт FIFO, только открывает.
fdOut_ = ::open(writePipe, O_WRONLY);
fdIn_ = ::open(readPipe, O_RDONLY);
}
~IpcPipeChannel() override {
if (fdIn_ >= 0) {
::close(fdIn_);
}
if (fdOut_ >= 0) {
::close(fdOut_);
}
}
void send(const std::string& data) override {
if (fdOut_ < 0) {
return;
}
::write(fdOut_, data.c_str(), data.size());
::write(fdOut_, "\n", 1);
}
std::string receive() override {
if (fdIn_ < 0) {
return {};
}
char buf[4096];
const int n = ::read(fdIn_, buf, sizeof(buf) - 1);
if (n <= 0) {
return {};
}
buf[n] = 0;
return std::string(buf);
}
private:
int fdIn_{-1};
int fdOut_{-1};
};

@ -1,9 +1,8 @@
#pragma once #pragma once
#include "RpcChannel.h" #include "RpcChannel.h"
#include "RpcSerializer.h" #include "IpcMessage.h"
#include <sstream>
#include <string> #include <string>
class RpcClient { class RpcClient {
@ -12,22 +11,22 @@ public:
template<typename Ret, typename... Args> template<typename Ret, typename... Args>
Ret call(const std::string& method, const Args&... args) { Ret call(const std::string& method, const Args&... args) {
std::ostringstream out; IpcMessageWriter msg;
// имя метода // имя метода
RpcSerializer::write(out, method); msg.add(method);
// аргументы // аргументы
(RpcSerializer::write(out, args), ...); (msg.add(args), ...);
// отправить // отправить
channel.send(out.str()); channel.send(msg.str());
// получить ответ // получить ответ
std::string resp = channel.receive(); std::string resp = channel.receive();
std::istringstream in(resp); IpcMessageReader reader(resp);
return RpcSerializer::read<Ret>(in); return reader.template read<Ret>();
} }
private: private:

@ -1,9 +1,8 @@
#pragma once #pragma once
#include "RpcSerializer.h" #include "IpcMessage.h"
#include <functional> #include <functional>
#include <sstream>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <unordered_map> #include <unordered_map>
@ -16,21 +15,19 @@ public:
Ret (Obj::*method)(Args...)) { Ret (Obj::*method)(Args...)) {
handlers[name] = handlers[name] =
[instance, method](const std::string& req) -> std::string { [instance, method](const std::string& req) -> std::string {
std::istringstream in(req); IpcMessageReader reader(req);
// пропустить имя метода // пропустить имя метода
std::string skip; (void)reader.template read<std::string>();
in >> skip;
// читать аргументы и вызвать метод // читать аргументы и вызвать метод
return callMethod<Ret, Obj, Args...>(instance, method, in); return callMethod<Ret, Obj, Args...>(instance, method, reader);
}; };
} }
std::string dispatch(const std::string& request) { std::string dispatch(const std::string& request) {
std::istringstream in(request); IpcMessageReader reader(request);
std::string method; const std::string method = reader.read<std::string>();
in >> method;
auto it = handlers.find(method); auto it = handlers.find(method);
if (it == handlers.end()) { if (it == handlers.end()) {
@ -44,19 +41,19 @@ private:
template<typename Ret, typename Obj, typename... Args> template<typename Ret, typename Obj, typename... Args>
static std::string callMethod(Obj* obj, static std::string callMethod(Obj* obj,
Ret (Obj::*method)(Args...), Ret (Obj::*method)(Args...),
std::istringstream& in) { IpcMessageReader& reader) {
auto tuple = readArgs<Args...>(in); auto tuple = readArgs<Args...>(reader);
Ret result = Ret result =
std::apply(method, std::tuple_cat(std::make_tuple(obj), tuple)); std::apply(method, std::tuple_cat(std::make_tuple(obj), tuple));
std::ostringstream out; IpcMessageWriter out;
RpcSerializer::write(out, result); out.add(result);
return out.str(); return out.str();
} }
template<typename... Args> template<typename... Args>
static std::tuple<Args...> readArgs(std::istringstream& in) { static std::tuple<Args...> readArgs(IpcMessageReader& reader) {
return std::tuple<Args...>{RpcSerializer::read<Args>(in)...}; return std::tuple<Args...>{reader.template read<Args>()...};
} }
std::unordered_map<std::string, std::unordered_map<std::string,

@ -1,48 +1,19 @@
#include "MyService.h" #include "MyService.h"
#include "MyService.skeleton.h" #include "MyService.skeleton.h"
#include "rpc/RpcChannel.h" #include "rpc/IpcPipeChannel.h"
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <iostream>
#include <string>
class RpcChannelFifoServer : public RpcChannel {
public:
RpcChannelFifoServer(const char* inPipe, const char* outPipe) {
fdIn = open(inPipe, O_RDONLY);
fdOut = open(outPipe, O_WRONLY);
}
void send(const std::string& data) override {
::write(fdOut, data.c_str(), data.size());
::write(fdOut, "\n", 1);
}
std::string receive() override {
char buf[4096];
int n = ::read(fdIn, buf, sizeof(buf) - 1);
if (n <= 0) {
return {};
}
buf[n] = 0;
return std::string(buf);
}
private:
int fdIn{};
int fdOut{};
};
int main() { int main() {
// Создание FIFO — часть пользовательского IPCкода.
mkfifo("/tmp/rpc_in", 0666); mkfifo("/tmp/rpc_in", 0666);
mkfifo("/tmp/rpc_out", 0666); mkfifo("/tmp/rpc_out", 0666);
RpcChannelFifoServer ch("/tmp/rpc_in", "/tmp/rpc_out"); // IPCуровень: канал поверх pipe.
IpcPipeChannel ch("/tmp/rpc_in", "/tmp/rpc_out");
// RPCуровень: скелет поверх того же канала.
MyService realObj; MyService realObj;
MyServiceSkeleton skeleton(realObj); MyServiceSkeleton skeleton(realObj);

Loading…
Cancel
Save