QNX操作系统信息传递-qnx任务之间的消息传递信息传递
2019-07-13 20:48发布
生成海报
如果你认为本系列文章对你有所帮助,请大家有钱的捧个钱场,点击此处赞助,赞助额1元起步,多少随意
锋影e-mail:174176320@qq.com一、QNX消息概述QNX消息可以分为同步消息和异步消息。异步(脉冲)消息主要体现的是一种通知机制,同步消息主要是说消息在传递过程需要双方相互配合的过程。二、QNX消息传递几个基本概念1、频道与链接消息传递是基于服务器与客户端的模式来进行的,QNX6抽象出了”频道“(Channel)这个概念。一个频道,就是一个服务的入口;至于这个频道到底具体有多少线程为其服务,那都是服务器端自己的事情。一个服务器如果有多个服务,它也可以开多个频道。而客户端,在向“频道”发送消息前,需要先建立连接(Connection),然后将消息在连接上发出去。这样同一个客户端,如果需要,可以与同一个频道建立多个连接。2、名字空间(name_space)在客户端与服务器通信中,为了让客户端方便的知道服务器的nd/pid/chid, 服务器进程可以注册一个路径名,与服务频道的nd, pid, chid关联起来。客户端就只要请求连接版务器路径名就可以了。三、QNX同步信号下客户端服务器通信1、客户端模型1)调用name_open(PATH)连接到服务器频道获得一个连接ID3)调用API发送消息等待服务器应答4)收到应答完毕调用name_close()关闭连接2、服务器模型1)调用name_attach注册一个名字空间并且创建一个频道2)接收并处理消息3)应答消息处理结果4)name_detach从名字空间删除该名称3、客户端服务器消息传递过程1)服务器注册一个名字空间等待客户端连接2)客户端连接到名字空间3)客户端调用MsgSend接口给服务器发送消息,客户端处于发送阻塞4)服务器调用MsgReceive接口接收数据,客户端处于应答阻塞5)服务器处理完毕消息,调用MsgReply函数发送应答消息6)客户端从MsgSend函数返回,解除阻塞4、利用多路消息传递提高效率用iov_t来“汇集”数据。也就是说,可以一次传送几块据。Header同databuf是两块不相邻的内存,但传递到服务器端的ReceiveBuffer里,就是连续的了。SETIOV(&iov[0], &header, sizeof(header));SETIOV(&iov[1], databuf, datalen);MsgSendvs(ConnectionId, iov, 2, Replybf, ReplyLen);5、消息传递的方向与MsgDeliverEvent()客户端给服务器发送消息,服务器不能立刻应答而客户端不想等待。遇到这种情况,正确的做法是,告诉客户端,请求一段时间后会得到处理,客户端得以继续运行,一旦服务器完成任务,服务器需要一些方式告诉客户端请求完成。客户端: 准备一个“通知事件”(Notification Event),并把这个事件用MsgSend()发给服务器端,意思是:“如果xxx情况发生的话,请用这个事件通知我”。 服务器: 收到这个消息后,记录下当时的rcvid,和传过来的事件,然后应答“好的,知道了”。 客户端: 因为有了服务器的应答,客户端不再阻塞,可以去做别的事 ...... 服务器: 在某个时刻,客户端所要求的“xxx情况”满足了,服务器调用 MsgDeliverEvent(rcvid, event);以通知客户端 客户端: 收到通知,再用MsgSend()发关“xxx 情况的数据在哪里?” 服务器: 用MsgReply()把数据返回给客户端 int MsgDeliverEvent (int rcvid,const struct sigevent *event);event服务器不需要作修改 rcvid是服务器从客户端接收的。当服务器给客户端应答后,这个id将失去意义。另外MsgDeliverEvent是非阻塞函数。6、常用APIChannelCreate(), ChannelDestroy() ConnectAttach(), ConnectDetach() MsgDeliverEvent() MsgError() MsgRead(), MsgReadv() MsgReceive(), MsgReceivePulse(), MsgReceivev() MsgReply(), MsgReplyv() MsgSend(), MsgSendnc(), MsgSendsv(), MsgSendsvnc(), MsgSendv(), MsgSendvnc(), MsgSendvs(), MsgSendvsnc() MsgWrite(), MsgWritev()name_attach(), name_close(), name_detach(), and name_open()7、总结1)客户端在给服务发送消息的时候指定服务器应答缓冲区2)服务器给客户端应答消息(MsgReply)的时候传递参数作为MsgSend返回值3)服务器在MsgReceive的时候可以传递参数用于获取客户端发送的消息的一些信息4)客户端在打开服务名字空间的时候系统会发送一个_IO_CONNECT 消息给服务器5)客户端断开连接或者关闭名字空间的时候服务器会收到_PULSE_CODE_DISCONNECT脉冲6)客户端视图从REPLY BLOCK解除阻塞的时候服务器会收到_PULSE_CODE_UNBLOCK脉冲7)创建名字空间的时候自动设置了_NTO_CHF_DISCONNECT_NTO_CHF_COID_DISCONNECT 、_NTO_CHF_UNBLOCK 标准,故服务器可以收到对应系统脉冲四、通知信号-脉冲1、基本概念脉冲其实更像一个短消息,也是在“连接”上发送的。脉冲最大的特点是它是异步的。发送方不必要等接收方应答,直接可以继续执行。但是,这种异步性也给脉冲带来了限制。脉冲能携带的数据量有限,只有一个8位的"code"域用来区分不同的脉冲,和一个32位“value"域来携带数据。脉冲最主要的用途就是用来进行“通知”(Notification)。不仅是用户程序,内核也会生成发送特殊的“系统脉冲”到用户程序,以通知某一特殊情况的发生。2、接收脉冲知道频道上不会有别的消息,只有脉冲的话,可以用MsgReceivePulse()来只接收脉冲;如果频道既可以接收消息,也可以接收脉冲时,就直接用MsgReceive(),只要确保接收缓冲(ReveiveBuf)至少可以容下一个脉冲(sizeof struct _pulse)就可以了。如果MsgReceive()返回的rcvid是0,就代表接收到了一个脉冲,反之,则收到了一个消息。3、脉冲信号特点1)有效传递40位数据(8位脉冲码,32位数据)2)对发送者而言是非阻塞的3)可以像其他消息一样被接受4)脉冲会排队,只要接受者不是阻塞等待脉冲。5)若没有脉冲,则接收者会阻塞等待脉冲4、相关数据结构与APIstruct _pulse { uint16_t type; uint16_t subtype; int8_t code; uint8_t zero [3]; union sigval value; int32_t scoid; };value是一个联合体 union sigval { int sival_int; void *sival_ptr; }; int MsgReceivePulse (int chid, void *rmsg, int rbytes, struct _msg_info *info);五、异步消息1、异步信号常用APIasyncmsg_channel_create()asyncmsg_channel_destroy()asyncmsg_connect_attach()asyncmsg_connect_detach()asyncmsg_flush()asyncmsg_put(),asyncmsg_get()asyncmsg_free()asyncmsg_malloc()2、API说明int asyncmsg_channel_create (unsigned flags,mode_t mode,size_t buffer_size,unsigned max_num_buffer,const struct sigevent *ev,int (*recvbuf_callback) (size_t bufsize,unsigned num_bufs,void *bufs[],int flags,void *handle ),void *recvbuf_callback_handle );Flags:描述频道属性,默认设置_NTO_CHF_ASYNC,如果设置_NTO_CHF_ASYNC_NONBLOCK 那么程序在调用asyncmsg_get()的时候如果没有消息到来将不会阻塞。Mode:设置频道属性Buff_size:设置存放消息的缓冲的大小Max_num_buffer:设置存放消息的缓冲区最大个数Ev:NULL或者一个指向sigevent结构体的指针,用于指定一个事件,当有消息可以被接收的时候这个事件自动发送Recvbuf_callback:NULL或者一个函数指针,用于分配空间存放接收的消息为NULL时候用Mallocrecvbuf_callback_handle:传递给Recvbuf_callback函数。说明:当Recvbuf_callback不为NULL的时候:每当调用一次asyncmsg_get()的时候触发一次回调函数(flags设置为ASYNCMSG_RECVBUF_ALLOC,bufs指向消息...)当希望接收其他消息的时候返回1,返回0停止。调用 asyncmsg_channel_destroy()的时候,回调函数被触发多次用于释放空间,flags设置为ASYNCMSG_RECVBUF_FREE。int asyncmsg_channel_destroy( int chid );chid :频道ID说明:当Recvbuf_callback不为NULL的时候,每次调用会触发释放空间,默认调用free。返回值:成功:EOK失败:-1 ->errnoint asyncmsg_connect_attach (uint32_t nd,pid_t pid,int chid,unsigned index,unsigned flags, const struct _asyncmsg_connection_attr * attr);参数说明:Nd/pid/chid:哪台电脑/进程ID/频道IDindex:最低可接受的连接ID(起始值)Flags:_NTO_COF_NOSHARE:应用程序使用自己的BUFFER,否则使用asyncmsg_malloc(),填充数据调用asyncmsg_put()的时候发送。_NTO_COF_NONBLOCK:不用阻塞等待,当发送头部忙的时候Attr:指定连接属性返回值:成功:连接ID失败:-1int asyncmsg_connect_detach( int coid );参数:coid :连接ID备注:从指定连接断开,所有在发送放一侧的消息被丢弃,如果为了在这之前所有的消息被发送完毕,在这之前调用asyncmsg_flush()接口。返回值:成功:EOK失败:-1int asyncmsg_flush( int coid,int mode );参数说明:Coid:连接IDMode:0,如果不想该函数阻塞则设置ASYNCMSG_FLUSH_NONBLOCK 返回值:成功:EOK失败:-1int asyncmsg_connect_attr (int coid,struct _asyncmsg_connection_attr *old_attr, const struct _asyncmsg_connection_attr *new_attr);参数说明:coid:连接IDOld_attr:当前属性new_attr:新的属性返回值:成功:EOK失败:-1int asyncmsg_put( int coid,const void *buff,size_t size, unsigned handle),int (*call_back) (int err,void* buf,unsigned handle ));int asyncmsg_putv( int coid,
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮