设计并实现了一个用于进程间通讯的对象。在实际使用中,进程间通讯可以细分为远程方法调用和远程事件。类似于前面所讲的对象系统中的方法和事件。远程事件的例子比如说系统中有A,B,C三个进程对u盘热插拔的事件感兴趣,但是不可能三个进程都去监视系统的u盘事件,因为直接去获取和过滤系统事件可能比较复杂(比如目前linux是通过udev写过滤器和udev事件接收程序)。可以专门写一个S程序来获取和过滤系统事件,然后触发一个远程事件发给A,B,C。远程方法的例子还是可以这个例子,有时候A进程可能想主动的向B查询一下当前的u盘设备。这时A就调用B的远程方法,并取回B的返回值。
也就是说远程事件是1对多,是被动接收的,没有返回值。并且A,B,C三者都需要先告诉S对什么事件感兴趣,这样S才知道事件发给谁。远程方法是1对1的,就是主动调用并要取回返回值。远程事件和方法是独立的,可以有也可以没有互相没有关系。
typedef DINT (*Gd_Remote_Method_Function)(void *msg_obj, GD_ID method, GD_TABLE *in_out, void *arg, GD_EXIST *exist); 远程方法的执行函数原型
typedef void (*Gd_Remote_Method_Return_Function)(void *msg_obj, GD_ID method, GD_TABLE *out, void *arg, DINT ret, GD_EXIST *exist); 接收远程方法返回值的回调函数原型
void *GdMessageCreate(char *name, Gd_Remote_Method_Function func, void *arg);创建一个远程消息通讯的对象,提供一个name,这个name是整个系统唯一的,如果已经存在相同名字的会创建不成功。提供一个远程方法的执行函数,这样其他进程才可以远程执行你的方法,如果你不提供别人调用的远程方法,这个参数为NULL,最后一个参数arg会复制给你的func中的参数arg.
DINT GdMessageRegisterRemoteEvent(void *msg_obj, char *remote, GD_ID event, Gd_Event_Function func, void *arg);该函数告诉远程的remote,我对你的event事件感兴趣,并且如果以后remote触发了该事件,回调执行我提供的函数func, arg会复制到func中的参数arg。
void GdMessageTriggerRemoteEvent(void *msg_obj, GD_ID event, GD_TABLE *in);触发远程事件,所有对msg_obj的event事件感兴趣的其他进程都会收到该事件调用相应的回调函数。参数in这个GD_TABLE也会原封不动的传递给其他进程的回调函数。比如上面的例子,当S检测到系统有u盘插入时,就执行GdMessageTriggerRemoteEvent(S, GD_STIRNG_ID(u_hotplug), NULL);
void GdMessageDeleteRemoteEvent(void *msg_obj, char *remote, GD_ID event);告诉remote,我对你的event事件不感兴趣了。
DINT GdMessageRemoteMethod(void *msg_obj, char *remote, GD_ID method, GD_TABLE *in, Gd_Remote_Method_Return_Function func, void *arg);执行remote的远程方法,参数in会原封不动的传递给remote的方法执行函数Gd_Remote_Method_Function.因为是远程方法,没有阻塞等待远程方法的返回结果. 该函数发包后就立即返回,所以用户还要提供一个Gd_Remote_Method_Return_Function func,在以后收到返回结果时会回调这个函数。
void GdMessageIgnoreRemoteReturn(void *msg_obj, char *remote, GD_ID method);忽略remote的远程方法返回结果。
const char *GdMessageGetRemote(void *msg_obj);在各种回调函数中调用该函数的到此时相应的远程进程的名字。
该进程间通讯对象的设计是p2p的,即每个进程的地位都是一样的,都可以既做client又做server,当然在实际使用中大多是一种身份。下面是一个简单的例子:
client:
void remote_method_return(void *msg_obj, GD_ID method, GD_TABLE *out, void *arg, DINT ret, GD_EXIST *exist)
{
printf("server method2 return %d, the table from remote is/n", ret);
GdTableDump(out);
return;
}
main()
{
void *client;
client = GdMessageCreate(GD_STRING_ID(client), NULL, NULL);
GdMessageRemoteMethod(client, "server", GD_STRING_ID(method1), NULL, NULL, NULL);
GdMessageRemoteMethod(client, "server", GD_STRING_ID(method2), NULL, remote_method_return, NULL);
while(1) GdTaskLoopOnce(0);
}
server:
void remote_method(void *msg_obj, GD_ID method, GD_TABLE *in_out, void *arg, GD_EXIST *exist)
{
if(method == GD_STRING_ID(method1))
printf("server got method1/n");
else if(method == GD_STRING_ID(method2))
printf("server got method2/n");
return;
}
main()
{
void *server;
server = GdMessageCreate(GD_STRING_ID(sever), NULL, NULL);
while(1) GdTaskLoopOnce(0);
}