简单的帐目客户和服务器

在这个第三个例子中,我们将看到如何设置一个能修改存储在服务器上的变量的值的客户程序。这是最基本的帐目管理工作的方式。存储的变量是 balance (余额)。对于我们这个帐目的 idl 定义(account.idl)是 :

Example 5-7. 帐目 IDL 文件

   interface Account {
      void deposit (in unsigned long amount);
      void withdraw (in unsigned long amount);
      readonly attribute long balance;
   };

帐目客户

设置客户没有什么难的(至少不比前一个例子复杂)。只增加了一件事:在调用服务器之前测试服务器是否是可获得的。(就是if (!acc_client)判断)

Example 5-8. 帐户客户源代码

/*------- Account client (account-client.c)-----------------------------------------*/
#include <stdio.h>
#include <orb/orbit.h>
#include "account.h" 
 
int main (int argc, char *argv[]) {

  Account acc_client;         /* The client-side Account object 
                                 客户端帐目对象 */
  CORBA_long val;             /* client stores the balance here
                                 客户在词存储余额 */
  PortableServer_POA poa;
  CORBA_ORB orb=NULL;         /* This is our ORB 这是我们的 ORB */
  char *ior;                  /* an IOR is one way a client can locate a server
                                 IOR 是客户定位服务器的一种方式*/
  CORBA_Environment ev;       /* CORBA exception information
                                 CORBA 例外信息 */

  CORBA_exception_init(&ev);

  /* 
   * Initialize the orb. The initialization routine checks the command
   * line parameters for directives that affect the orb
   * 初始化 orb。初始化例程检查命令行参数,找出影响 orb 的指示
   */
   
  orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", &ev);
 
  /*
   * Bind  our client Account to the account on the server using the
   * IOR to look it up (the ior was gotten above in the server code)
   * 把我们的客户 Account 绑定到用 IOR 找到的帐目上( IOR 在服务器代码中获得)
   */

  acc_client = CORBA_ORB_string_to_object(orb, argv[1], &ev);
  if (!acc_client) {
    printf("Cannot bind to %s\n (pass the IOR as arg 1)\n", argv[1]);
    exit(1);
  }
  val = Account__get_balance(acc_client, &ev);
  printf ("Initial balance is %d.\n",val);

  printf("Make a deposit, how :");
  scanf("%d",&val); 
  Account_deposit(acc_client, (CORBA_unsigned_long) val, &ev);
  val = Account__get_balance(acc_client, &ev);
  printf ("Balance is %d.\n",val);

  Account_withdraw(acc_client, (CORBA_unsigned_long) 5, &ev);
  val = Account__get_balance(acc_client, &ev);
  printf ("Balance is %d.\n",val);

  /*
   * We're done now. Do some cleanup
   * 我们完工了,做些清理
   */
   
  CORBA_Object_release(acc_client, &ev);
  exit (0);
}

帐目服务器

对于服务器,象在上个例子中那样,我们先生成源文件 account-skelimpl.c ,在其中加入方法的实现代码。这是通过 orbit-idl --skeleton-impl account.idl 做的。

现在我们编辑 account-skelimpl.c 文件。我们找到在 IDL 文件中定义的 balance 属性。在文件的开头,我们可发现被 idl 编译器转换成 C 的方式。

Example 5-9. 帐目服务器的框架实现

/*** App-specific servant structures ***/
typedef struct {
POA_Account servant;
PortableServer_POA poa;

CORBA_long attr_balance;

} impl_POA_Account;

所以,服务器的方法(withdraw 和 deposit)必须通过 servant->attr_balance 来管理帐目的余额(servant 变量被作为参数传递给每个方法)。

现在我们到文件的后面找到方法的存根。我们找到了 impl_Account_* 函数,在里面加上实现代码。代码可能象这样:

static void
impl_Account_deposit(impl_POA_Account *servant,
CORBA_unsigned_long amount,
CORBA_Environment *ev)
{
    printf("server calls deposit method...\n");
    servant->attr_balance += amount;
}

static void
impl_Account_withdraw(impl_POA_Account *servant,
CORBA_unsigned_long amount,
CORBA_Environment *ev)
{
    printf("server calls withdraw method...\n");
    servant->attr_balance -= amount;
}

static CORBA_long
impl_Account__get_balance(impl_POA_Account *servant,
CORBA_Environment *ev)
{
CORBA_long retval;
     retval= servant->attr_balance;
return retval;
}

最后,我们写一些更一般的代码来建立服务器。我们叫它 account-server.c。它同计算器和 echo 例子的代码大致上相同。这些代码只是初始化 ORB 并为服务器的对象公布一个 IOR。

Example 5-10. 帐目服务器的 C 源代码

/*------- Account server (account-server.c)-----------------------------------------*/
#include "account-skelimpl.c"
#include <stdio.h>

int main (int argc, char *argv[]) {
  CORBA_ORB                 orb;
  CORBA_Environment*        ev;
  PortableServer_ObjectId*  oid;
  Account                   account;
  PortableServer_POA        root_poa;
  PortableServer_POAManager pm;
  CORBA_char*               ior;

  ev = g_new0(CORBA_Environment,1);
  CORBA_exception_init(ev);
  
  /* 
   * Initialize the orb. The initialization routine checks the command
   * line parameters for directives that affect the orb
   * 初始化 orb。初始化例程检查命令行参数,找出影响 orb 的指示
   */
   
  orb = CORBA_ORB_init(&argc, argv, "orbit-local-orb", ev);

  root_poa = (PortableServer_POA)
    CORBA_ORB_resolve_initial_references(orb, "RootPOA", ev);

  /* 
   * ask for instanciation of one object account
   * 要求建立一个 account 对象的实例
   */
  account = impl_Account__create(root_poa, ev);

  /*
   * Here we get the IOR for the acc object.  Our "client" will use
   * the IOR to  find the server to connect to
   * 这里我们得到 acc 对象的 IOR。我们的 "client" 将使用
   * IOR 找到服务器并连接上
   */
   
  ior = CORBA_ORB_object_to_string(orb, account, ev);

  /* 
   * print out the IOR, just so you can see what it looks like
   * 输出 IOR,这样你可以看到它的实际样子
   */
  printf ("%s\n", ior);

  pm = PortableServer_POA__get_the_POAManager(root_poa, ev);
  PortableServer_POAManager_activate(pm,ev);

  CORBA_ORB_run(orb, ev);
  return (0);
}

编译服务器和客户

Makefile 大致上同于上个计算器例子。这里介入了一些变化使它更加可定制化(customizable)。通过改变 PROJECT 变量,你可在大量的小工程中重用这个 Makefile。

Example 5-11. 帐目例子程序的 Makefile

PROJECT = account
CC = gcc
ORBIT_IDL = /usr/bin/orbit-idl
ORBIT_CFLAGS = -I/usr/lib/glib/include -I/usr/include
ORBIT_LIBS = -L/usr/lib -lORBit -lIIOP -lORBitutil -lglib -lm
CFLAGS = $(ORBIT_CFLAGS)
LFLAGS = $(ORBIT_LIBS)

all : idltargets $(PROJECT)-client $(PROJECT)-server

$(PROJECT)-client : $(PROJECT)-client.o $(PROJECT)-common.o $(PROJECT)-stubs.o
    $(CC) -o $(PROJECT)-client $(PROJECT)-client.o $(PROJECT)-stubs.o $(PROJECT)-common.o  -lIIOP -lORBit -lORBitutil $(LFLAGS)

$(PROJECT)-server : $(PROJECT)-server.o $(PROJECT)-skels.o $(PROJECT)-common.o
    $(CC) -o $(PROJECT)-server $(PROJECT)-server.o $(PROJECT)-skels.o $(PROJECT)-common.o  -lIIOP -lORBit -lORBitutil $(LFLAGS)


clean :
    rm *.[oa] $(PROJECT)-client $(PROJECT)-server

real-clean : clean
    rm -f $(PROJECT)-stubs.[oc] $(PROJECT)-skels.[oc] $(PROJECT).h $(PROJECT)-common.[oc]
 
idltargets : $(PROJECT).idl
    $(ORBIT_IDL) $(PROJECT).idl

# individual rules

$(PROJECT)-stubs.c : $(PROJECT).idl
    $(ORBIT_IDL) $(PROJECT).idl

$(PROJECT)-common.c : $(PROJECT).idl
    $(ORBIT_IDL) $(PROJECT).idl

$(PROJECT)-skels.c : $(PROJECT).idl
    $(ORBIT_IDL) $(PROJECT).idl

$(PROJECT)-client.c : $(PROJECT).h

$(PROJECT)-server.c : $(PROJECT).h

$(PROJECT).h : $(PROJECT).idl
    $(ORBIT_IDL) $(PROJECT).idl