一、c++ 和 c# 通信
c# 端服务器 如果域名 输入的是 https ,则 c++ 端需要匹配使用,也就是c++ 端需要进行安全认证。如果是http 则c++ 端不需要认证(基于c#的grpc 未 通信成功)
参考如下网址可以写一个简单的 .net grpc服务器 (无论是https 还是 http 都通信成功),工程中的launchSettings.json 可设置监听的域名与端口,
二、.net 知识
在运行 .NET Core 应用程序时,提示使用 SSL(即 HTTPS),通常情况下,.NET Core 可以生成自签名证书来简化开发和测试过程。以下是一些常见的情况和配置:
自签名证书生成
在开发环境中,.NET Core SDK 会自动生成自签名证书,以便于使用 HTTPS。这些证书通常会在本地的开发环境中创建,并由 ASP.NET Core 自带的开发证书工具 (dotnet dev-certs) 进行管理。你可以通过以下命令生成或管理这些证书:
dotnet dev-certs https –trust
这个命令会生成一个自签名证书并将其标记为受信任,适用于本地开发和测试。
在生产环境中的证书
在生产环境中,通常需要使用由受信任的证书颁发机构(CA)签发的证书。你需要从 CA 处获得证书,并将其配置到你的 Web 服务器中(如 Kestrel、IIS、NGINX 等)。
总结
- 开发环境:.NET Core SDK 会自动生成并管理自签名证书。
- 生产环境:你需要从受信任的 CA 获得证书,并在 Web 服务器中配置它。
确保在生产环境中使用正确的证书和配置,以确保安全性。
在 开发 c++ grpc 客户端 与 c# 服务端时 ,c# 程序就是默认使用的 https , 所以c++ 客户端需要如果需要连接的话,,就必须使用认证,,需要一个证书
根据上述截图的 dotnet dev-certs https -ep ./certificate.crt --trust --format PEM 可导出证书文件。
三、c++ grpc 客户端认证。。只需要输入认证文件就可以了
//客户端应用
void EventClientTest()
{
//读文件
auto ReadFile = [](const std::string& filename) {
std::ifstream file(filename);
if (!file.is_open()) {
throw std::runtime_error("Unable to open file: " + filename);
}
return std::string((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
};
// 配置 SSL 证书
grpc::SslCredentialsOptions ssl_opts;
//ssl_opts.pem_root_certs = ReadFile("certificate.crt"); // 服务器证书
ssl_opts.pem_root_certs = ReadFile("server.crt"); // 服务器证书
auto creds = grpc::SslCredentials(ssl_opts);
// 创建 SSL 凭据
auto credentials = grpc::SslCredentials(ssl_opts);
//创建 grpc 通道
EventClient enent(grpc::CreateChannel(
"localhost:6001", credentials));
//不认证的方式
// EventClient enent(grpc::CreateChannel(
// "localhost:6001", grpc::InsecureChannelCredentials()));
// std::string user("world");
// std::string reply = enent.Dispatch(user);
// qDebug() << "Greeter received: " << reply.c_str();
//rpc 调用
enent.SubDispatch();
}
四、c++ grpc 服务端
需要自己使用openssl 工具生成 证书,
生成 key:
openssl genpkey -algorithm RSA -out server.key -pkeyopt rsa_keygen_bits:2048
生成证书:CN 是域名。。:
openssl req -new -x509 -key server.key -out server.crt -days 365 -subj "/CN=localhost"
试了 该域名支持服务器ip 为 localhost 和 0.0.0.0 的连接
void GrpcServer::serverWait()
{
std::string server_address = absl::StrFormat("%s:%d", m_ip, m_port);
grpc::EnableDefaultHealthCheckService(true);
grpc::reflection::InitProtoReflectionServerBuilderPlugin();
//读文件
auto ReadFile = [](const std::string& filename) {
std::ifstream file(filename);
if (!file.is_open()) {
throw std::runtime_error("Unable to open file: " + filename);
}
return std::string((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
};
//服务端则需要两个,一个是密钥,一个认证文件
std::string server_cert = ReadFile("./server.crt");
std::string server_key = ReadFile("./server.key");
std::string ca_cert = ""; //ca 认证文件是需要向机构申请的,自用不需要
// 设置服务器证书
grpc::SslServerCredentialsOptions::PemKeyCertPair key_cert_pair;
key_cert_pair.private_key = server_key;
key_cert_pair.cert_chain = server_cert;
grpc::SslServerCredentialsOptions ssl_opts;
ssl_opts.pem_key_cert_pairs.push_back(key_cert_pair);
ssl_opts.pem_root_certs = ca_cert;
// 创建服务器凭证
auto server_creds = grpc::SslServerCredentials(ssl_opts);
ServerBuilder builder;
// Listen on the given address without any authentication mechanism.
builder.AddListeningPort(server_address, server_creds);
// Register "service" as the instance through which we'll communicate with
// clients. In this case it corresponds to an *synchronous* service.
for(auto service : m_listService)
{
builder.RegisterService(service.get());
}
// Finally assemble the server.
m_server = builder.BuildAndStart();
qCritical() << "Server listening on " << 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.
m_server->Wait();
}