如何在 C++ 中使用 RPC (msdn) 来回发送消息

问题描述

我正在尝试编写一个 RPC 服务器应用程序和一个 RPC 客户端应用程序,以便来回发送消息。

按照本教程,我可以成功地从客户端向服务器发送消息:https://www.codeproject.com/Articles/4837/Introduction-to-RPC-Part-1。现在修改代码,以便服务器也可以将响应发送回客户端。

这是我的 IDL 文件

import "oaidl.idl";
import "ocidl.idl";
[
    // A unique identifier that distinguishes this
    // interface from other interfaces.
    uuid(00000001-EAF3-4A7A-A0F2-BCE4C30DA77E),// This is version 1.0 of this interface.
    version(1.0),// This interface will use an implicit binding
    // handle named hExample1Binding.
    implicit_handle(handle_t hExample1Binding)
]
interface Example1 // The interface is named Example1
{
    // A function that takes a zero-terminated string.
    void Output(
        [in,string] const char* szInput,[out,string,size_is(500)] const char* szOutput);
}

这是我的服务器代码

// PlainRPCServer.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"



// File ContextExampleServer.cpp

#include <string>
#include <iostream>
#include "Example1_h.h"

using namespace std;

// Server function.
void Output(
    /* [string][in] */ const unsigned char *szInput,/* [size_is][string][out] */ const unsigned char *szOutput)
{
    std::cout << "from client " << szInput << std::endl;
    szOutput = "Reply from the server";
    return;
}

// Naive security callback.
RPC_STATUS CALLBACK SecurityCallback(RPC_IF_HANDLE /*hInterface*/,void* /*pBindingHandle*/)
{
    return RPC_S_OK; // Always allow anyone.
}

int main()
{
    RPC_STATUS status;

    // Uses the protocol combined with the endpoint for receiving
    // remote procedure calls.
    status = RpcServerUseProtseqEpA(
        (RPC_CSTR)("ncacn_ip_tcp"),// Use TCP/IP protocol.
        RPC_C_PROTSEQ_MAX_REQS_DEFAULT,// Backlog queue length for TCP/IP.
        (RPC_CSTR)("4747"),// TCP/IP port to use.
        NULL);                          // No security.

    if (status)
        exit(status);

    // Registers the Example1 interface.
    status = RpcServerRegisterIf2(
        Example1_v1_0_s_ifspec,// Interface to register.
        NULL,// Use the MIDL generated entry-point vector.
        NULL,// Use the MIDL generated entry-point vector.
        RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH,// Forces use of security callback.
        RPC_C_LISTEN_MAX_CALLS_DEFAULT,// Use default number of concurrent calls.
        (unsigned)-1,// Infinite max size of incoming data blocks.
        SecurityCallback);                   // Naive security callback.

    if (status)
        exit(status);

    // Start to listen for remote procedure
    // calls for all registered interfaces.
    // This call will not return until
    // RpcMgmtStopServerListening is called.
    status = RpcServerListen(
        1,// Recommended minimum number of threads.
        RPC_C_LISTEN_MAX_CALLS_DEFAULT,// Recommended maximum number of threads.
        FALSE);                              // Start listening Now.

    if (status)
        exit(status);
}

// Memory allocation function for RPC.
// The runtime uses these two functions for allocating/deallocating
// enough memory to pass the string to the server.
void* __RPC_USER midl_user_allocate(size_t size)
{
    return malloc(size);
}

// Memory deallocation function for RPC.
void __RPC_USER midl_user_free(void* p)
{
    free(p);
}

服务器正在使用此代码运行。但是,由于客户端不工作,我不确定服务器是否正常工作。

这是我客户的代码

// PlainRPcclient.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include "Example1_h.h"
using namespace std;


int main()
{
    RPC_STATUS status;
    RPC_CSTR szStringBinding = NULL;

    // Creates a string binding handle.
    // This function is nothing more than a printf.
    // Connection is not done here.
    status = RpcStringBindingComposeA(
        NULL,// UUID to bind to.
        (RPC_CSTR)("ncacn_ip_tcp"),// Use TCP/IP protocol.
        (RPC_CSTR)("localhost"),// TCP/IP network address to use.
        (RPC_CSTR)("4747"),// TCP/IP port to use.
        NULL,// Protocol dependent network options to use.
        &szStringBinding);                       // String binding output.

    if (status)
        exit(status);

    // Validates the format of the string binding handle and converts
    // it to a binding handle.
    // Connection is not done here either.
    status = RpcBindingFromStringBindingA(
        szStringBinding,// The string binding to validate.
        &hExample1Binding);     // Put the result in the implicit binding
                                // handle defined in the IDL file.

    if (status)
        exit(status);

    RpcTryExcept
    {
        // Calls the RPC function. The hExample1Binding binding handle
        // is used implicitly.
        // Connection is done here.
        const unsigned char* serverMsg = NULL;
        Output((const unsigned char *)"msg from the client",serverMsg);
    }
        RpcExcept(1)
    {
        std::cerr << "Runtime reported exception " << RpcExceptionCode()
            << std::endl;
    }
    RpcEndExcept

        // Free the memory allocated by a string.
        status = RpcStringFreeA(
            &szStringBinding); // String to be freed.

    if (status)
        exit(status);

    // Releases binding handle resources and disconnects from the server.
    status = RpcBindingFree(
        &hExample1Binding); // Frees the implicit binding handle defined in the IDL file.

    if (status)
        exit(status);
}

// Memory allocation function for RPC.
// The runtime uses these two functions for allocating/deallocating
// enough memory to pass the string to the server.
void* __RPC_USER midl_user_allocate(size_t size)
{
    return malloc(size);
}

// Memory deallocation function for RPC.
void __RPC_USER midl_user_free(void* p)
{
    free(p);
}

我的客户端代码终止于:运行时报告异常 1780

注意:我使用的是 VS2015(以防万一)。

我的问题:

  1. 从客户端调用远程方法输出”有问题,但我想不通。 serverMsg = NULL 的原因可以在 https://docs.microsoft.com/en-us/windows/win32/rpc/idl-techniques-for-better-interface-and-method-design 中找到(客户端应用程序组件在调用 RPC 方法时必须将 ppStr(对于我的代码是 serverMsg)设置为 NULL。)
  2. 如何将消息从服​​务器发送回客户端?我在 MSDN 中找不到这个例子。 (目前,我只是这样做:szOutput = "Reply from the server" 在服务器代码中)
  3. 以及如何在客户端应用程序中处理接收到的消息? (我的意思是如何分配消息并在客户端中使用它)?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)