- 客户端与服务端的通信模型
- client线程调用
MsgSend()
往server线程发送消息时会阻塞住,client线程进入Send blocked状态,直到server线程调用MsgReceive()
,client线程进入Reply blocked状态,server线程进行消息处理并调用MsgReply()
回复后才会解除阻塞。 - server线程调用MsgReceive()时,没有client线程发来消息,server线程状态为RECEIVE blocked状态,当收到消息(也就是client调用MsgSend()),状态变回READY状态。并且回复MsgReply(),从而进入ready状态。
- QNX中name_attach 和nameopen---
服务器端:name_attach():是在服务器端使用,在名称空间中定义一个name(客户端中对应open这个name),同时创建了一个channel.
name_attach_t * name_attach( dispatch_t * dpp,
const char * path, //对应name
unsigned flags );
typedef struct _name_attach {
dispatch_t* dpp;
int chid; //对应 channel id
int mntid;
int zero[2];
} name_attach_t;
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/dispatch.h>
#define ATTACH_POINT "myname"
/* We specify the header as being at least a pulse */
typedef struct _pulse msg_header_t;
/* Our real data comes after the header */
typedef struct _my_data {
msg_header_t hdr;
int data;
} my_data_t;
/*** Server Side of the code ***/
int server() {
name_attach_t *attach;
my_data_t msg;
int rcvid;
//Server端创建一个名为ATTACH_POINT的channel,用于client端创建Connect
if ((attach = name_attach(NULL, ATTACH_POINT, 0)) == NULL) {
return EXIT_FAILURE;
}
/* Do your MsgReceive's here now with the chid */
while (1) {
rcvid = MsgReceive(attach->chid, &msg, sizeof(msg), NULL);
if (rcvid == -1) {/* Error condition, exit */
break;
}
//OS还支持固定大小的非阻塞消息。这些被称为脉冲并携带一个小负载(四个字节的数据加一个字节码)。
//pulse包含一个相对较小的有效负载——8位代码和32位数据。脉冲常被用作中断处理程序中的通知机制。
//还允许服务器在不阻塞客户机的情况下向客户机发送信号
if (rcvid == 0) {/* Pulse received */
switch (msg.hdr.code) {
case _PULSE_CODE_DISCONNECT:
/*
* A client disconnected all its connections (called
* name_close() for each name_open() of our name) or
* terminated
*/
ConnectDetach(msg.hdr.scoid);
break;
case _PULSE_CODE_UNBLOCK:
/*
* REPLY blocked client wants to unblock (was hit by
* a signal or timed out). It's up to you if you
* reply now or later.
*/
break;
default:
/*
* A pulse sent by one of your processes or a
* _PULSE_CODE_COIDDEATH or _PULSE_CODE_THREADDEATH
* from the kernel?
*/
break;
}
continue;
}
/* name_open() sends a connect message, must EOK this */
if (msg.hdr.type == _IO_CONNECT ) {
MsgReply( rcvid, EOK, NULL, 0 );
continue;
}
/* Some other QNX IO message was received; reject it */
if (msg.hdr.type > _IO_BASE && msg.hdr.type <= _IO_MAX ) {
MsgError( rcvid, ENOSYS );
continue;
}
/* A message (presumable ours) received, handle */
printf("Server receive %d \n", msg.data);
MsgReply(rcvid, EOK, 0, 0);
}
//删除在Server端的这个Channel,由name_attach()返回值决定
name_detach(attach, 0);
return EXIT_SUCCESS;
}
/*** Client Side of the code ***/
int client() {
my_data_t msg;
int server_coid;
//发送消息的线程需要与接受消息的channel建立connection
if ((server_coid = name_open(ATTACH_POINT, 0)) == -1) {
return EXIT_FAILURE;
}
/* We would have pre-defined data to stuff here */
msg.hdr.type = 0x00;
msg.hdr.subtype = 0x00;
/* Do whatever work you wanted with server connection */
for (msg.data=0; msg.data < 5; msg.data++) {
printf("Client sending %d \n", msg.data);
if (MsgSend(server_coid, &msg, sizeof(msg), NULL, 0) == -1) {
break;
}
}
/* Close the connection */
name_close(server_coid);
return EXIT_SUCCESS;
}
int main(int argc, char **argv) {
int ret;
if (argc < 2) {
printf("Usage %s -s | -c \n", argv[0]);
ret = EXIT_FAILURE;
}
else if (strcmp(argv[1], "-c") == 0) {
printf("Running Client ... \n");
ret = client(); /* see name_open() for this code */
}
else if (strcmp(argv[1], "-s") == 0) {
printf("Running Server ... \n");
ret = server(); /* see name_attach() for this code */
}
else {
printf("Usage %s -s | -c \n", argv[0]);
ret = EXIT_FAILURE;
}
return ret;
}
- 编译生成可执行文件main
- ./main -s 执行服务端程序
- ./main -c 执行客户端程序