频道(Channel)与连接(Connect)
消息传递是基于服务器与客户端的模式来进行的,那么客户端怎样才能与服务器端通讯呢?最简单的,当然是指定对方的进程号。要发送的一方,将消息加一个头,告诉内核“把这个消息发给pid 12345”就行了。其实这也是QNX4时候的做法。但QNX6开始完整支持POSIX线程后,这种方法似乎就不太适合了。如果服务器,有两个线程,分别进行不同的服务,那该怎么办呢?或者你会说“把这个消息发给pid 12345 tid 3”就行了。可是,如果某一个服务,不是由单一线程来进行服务的,而是有一组线程进行的,那又怎么办呢?为此,QNX6抽象出了”频道“(Channel)这个概念。一个频道,就是一个服务的入口;至于这个频道到底具体有多少线程为其服务,那都是服务器端自己的事情。一个服务器如果有多个服务,它也可以开多个频道。而客户端,在向“频道”发送消息前,需要先建立连接(Connection),然后将消息在连接上发出去。这样同一个客户端,如果需要,可以与同一个频道建立多个连接。
服务器
代码: 全选
ChannelId = ChannelCreate(Flags);
客户端
代码: 全选
ConnectionId = ConnectAttach(Node, Pid, Chid, Index, Flag);
Node:是机器号,如果存在网络分布处理,这个值将决定那台机器;如果服务器和客户端在同一个板子里,就是0。
PID:进程编号;
CHID:频道号;
常用API函数
extern int ChannelCreate(unsigned __flags);
extern int ChannelCreate_r(unsigned __flags);
extern int ChannelCreateExt(unsigned __flags, mode_t __mode, size_t __bufsize, unsigned __maxnumbuf, const struct sigevent *__ev, struct _cred_info *__cred);
extern int ChannelDestroy(int __chid);
extern int ChannelDestroy_r(int __chid);
extern int ConnectAttach(_Uint32t __nd, pid_t __pid, int __chid, unsigned __index, int __flags);
extern int ConnectAttach_r(_Uint32t __nd, pid_t __pid, int __chid, unsigned __index, int __flags);
extern int ConnectAttachExt(_Uint32t __nd, pid_t __pid, int __chid, unsigned __index, int __flags, struct _asyncmsg_connection_descriptor *__cd);
extern int ConnectDetach(int __coid);
extern int ConnectDetach_r(int __coid);
extern int MsgReceive(int __chid, void *__msg, int __bytes, struct _msg_info *__info);
extern int MsgReceive_r(int __chid, void *__msg, int __bytes, struct _msg_info *__info);
extern int MsgReply(int __rcvid, int __status, const void *__msg, int __bytes);
extern int MsgReply_r(int __rcvid, int __status, const void *__msg, int __bytes);
extern int MsgRead(int __rcvid, void *__msg, int __bytes, int __offset);
extern int MsgRead_r(int __rcvid, void *__msg, int __bytes, int __offset);
连接的终止是ConnectDetach(),而频道的结束则是ChannelDestroy()了。不过,一般服务器都是长久存在的,不大有需要ChannelDestroy()的时候。
发送(Send),接收(Receive)和应答(Reply)
QNX的消息传递,与我们传统常见的进程间通讯最大的不同,就是这是一个"同步的"消息传递。一个消息传递,都要经过发送,接收和应答三个部份,所谓的 SRR过程。具体来说,客户端在连接上"发送"消息,一旦发送,客户端会被阻塞,服务器端会接收到消息,进行处理,最后,将处理结果"应答"给客户端;只有服务器"应答"了以后,客户端的阻塞状态才会被解除。这种同步的过程,不但保证的客户端与服务器端的时序,也大大简化了编程。具体用API来说,就是这样。
#include
#include
#include
#include
#include
#include
#define MY_PULSE_CODE _PULSE_CODE_MINAVAIL
typedef union {
struct _pulse pulse;
/* your other message structures would go
here too */
} my_message_t;
int main(int argc, char *argv[])
{
struct sigevent event;
struct itimerspec itime;
timer_t timer_id;
int chid;
int rcvid;
my_message_t msg;
chid = ChannelCreate(0);/*创建通道*/
event.sigev_notify = SIGEV_PULSE;
event.sigev_coid = ConnectAttach(ND_LOCAL_NODE, 0,
chid,
_NTO_SIDE_CHANNEL, 0);
event.sigev_priority = getprio(0);
event.sigev_code = MY_PULSE_CODE;
timer_create(CLOCK_REALTIME, &event, &timer_id);
/*it_value 设定的是第一次初始化值*/
itime.it_value.tv_sec =1;
/* 500 million nsecs = .5 secs */
itime.it_value.tv_nsec = 500000000;
/*it_interval 设定的是每次间隔值*/
itime.it_interval.tv_sec = 0;
/* 500 million nsecs = .5 secs */
itime.it_interval.tv_nsec = 100000000;
timer_settime(timer_id, 0, &itime, NULL);
/*
* As of the timer_settime(), we will receive our pulse
* in 1.5 seconds (the itime.it_value) and every 1.5
* seconds thereafter (the itime.it_interval)
*/
for (;;) {
rcvid = MsgReceive(chid, &msg, sizeof(msg), NULL);
if (rcvid == 0) { /* we got a pulse */
if (msg.pulse.code == MY_PULSE_CODE) {
printf("we got a pulse from our timer\n");
} /* else other pulses ... */
} /* else other messages ... */
}
}