CORBA IIOPNet 和 OmniORBpy,值类型参数的远程方法调用问题

3 投票
1 回答
736 浏览
提问于 2025-04-17 00:37

我的情况是:我正在为两个应用程序创建一个CORBA解决方案,一个在.NET端(服务器),另一个在Python端(客户端)。我使用IIOPNet来处理服务器和IDL的生成,使用OmniORBpy来生成存根和客户端调用。总体来说,对于简单的调用,比如典型的加法器示例,运行得还不错。但是当我尝试调用一个带有自定义类的方法时,它就不工作了。

我在服务器端有这个类(我的远程对象),客户端需要调用它:

public class MyRemoteObject : MarshalByRefObject
{
    public override object InitializeLifetimeService()
    {
        return null;
    }

    public bool DoSomething(InterfaceRequest requestData)
    {
        return true;
    }

}

输入参数的类类型在服务器端是这样声明的(相当简单):

[Serializable]    
public class InterfaceRequest
{
    public int SiteId;
    public int UserId;
}

我使用CLSIDLGenerator生成IDL,然后用“omniidl -bpython -CPython ...”生成Python的存根,到这里一切正常。

然后我启动服务器(在VS调试环境中),现在在我的客户端代码中,我解析服务名称,成功缩小了我的远程对象,并创建了请求对象,但当我尝试这样做时:

request = InterfaceRequest()
request.SiteId = 1
request.UserId = 3

result = remoteObj.DoSomething(request) 

Python直接崩溃,没有任何警告,没有异常,也没有任何信息(我在omniORB配置文件中将跟踪标签更新到最高[40],但没有任何跟踪信息),它就是崩溃了。我尝试了很多方法,结果总是一样。问题当然与参数有关(我猜)。

我在客户端这样运行: python client.py -ORBInitRef NameService=corbaname::localhost:8087

(我最后的尝试是:Python对象引用架构和按值传递的符合值类型参数在某些地方不匹配)

技术细节: NET 4.0, IIOPNet(最新版本),Python 2.6,omniORB-4.1.5,omniORBpy-3.5。

任何帮助都非常感谢,我在这方面有点卡住了,谢谢。


是的,为MyRemoteObject生成的IDL是这个: .....

module module1 {
module module2 {
module module3 {
module module4 {

interface MyRemoteObject {

boolean TestConnection(in double value) 
raises (::Ch::Elca::Iiop::GenericUserException);

bool DoSomenthing(in ::module1::module2::module3::InterfaceRequest requestData) 
raises (::Ch::Elca::Iiop::GenericUserException);
};

.....

但现在你提到这个,我刚刚注意到在那个文件(myRemoteObject.idl)中,我有一个表示InterfaceRequest类型的结构,但它是空的,如下所示:

module module1 {
module module2 {
module module3 {

valuetype InterfaceRequest;

};
};
};

当然,我在其他地方生成了那个IDL,并且内容是正确的:

valuetype InterfaceRequest {
public long SiteId;
public long UserId;
};

奇怪,也许是我生成这些东西的顺序,这个顺序重要吗?显然这里有些地方出错了,对吧?

最后,我为这几个类(远程和参数类型)生成的Python存根看起来是这样的:

class _objref_MyRemoteObject (CORBA.Object):
    _NP_RepositoryId = MyRemoteObject._NP_RepositoryId

    def __init__(self):
        CORBA.Object.__init__(self)

    def TestConnection(self, *args):
        return _omnipy.invoke(self, "TestConnection", _0_module1.module2.module3.module4.MyRemoteObject._d_TestConnection, args)

    def DoSomething(self, *args):
        return _omnipy.invoke(self, "DoSomething", _0_module1.module2.module3.module4.MyRemoteObject._d_DoSomething, args)

    __methods__ = ["TestConnection", "DoSomething"] + CORBA.Object.__methods__

还有InterfaceRequest:

class InterfaceRequest (_0_CORBA.ValueBase):
    _NP_RepositoryId = "IDL:module1/module2/module3/InterfaceRequest:1.0"

    def __init__(self, *args, **kwargs):
        if args:
            if len(args) != 2:
                raise TypeError("InterfaceRequest() takes 2 arguments "
                                "(%d given)" % len(args))
            self.SiteId = args[0]
            self.UserId = args[1]
        if kwargs:
            self.__dict__.update(kwargs)

所以即使IDL可能不太正确(我只是猜测),最终生成的Python存根内容和路径都是正确的。

谢谢你的帮助(我已经更改了真实名称,希望这没关系),抱歉帖子这么长。

1 个回答

1

我觉得你忘了添加由IDLCompiler生成的接口存根。

public class MyRemoteObject : MarshalByRefObject, module1.module2.module3.MyRemoteObject
{
    public override object InitializeLifetimeService()
    {
        return null;
    }

    public bool DoSomething(InterfaceRequest requestData)
    {
        return true;
    }    
}

你需要按照下面的规则在C#中实现这个值类型: [现在这不是你的错误,但你迟早会遇到这个错误]。

  • 你需要实现一个类叫做XYZImpl,其中XYZ是值类型的名称
  • XYZImpl要继承自一个抽象类XYZ(这个类是由IDLToCLSgenerator生成的)
  • XYZImpl和XYZ要在同一个命名空间里
  • XYZImpl必须是可序列化的
  • XYZImpl需要有一个没有参数的公共构造函数
  • XYZImpl不能是抽象类
  • XYZImpl要实现所有继承来的抽象方法和属性 链接

记得,你需要打开一个IIOPServerChannel,方法是:

int port = 0;
IiopChannel chan = new IiopChannel(port);
ChannelServices.RegisterChannel(chan);

撰写回答