2. 进程间通信之消息传递
任务目标
本案例实现两个独立进程通过QNX消息传递机制完成一次请求-响应通信:发送进程调用MsgSend()向接收进程发送字符串消息,接收进程调用MsgReceive()接收后,使用MsgReply()回复确认信息。通过该案例掌握QNX消息传递的三个核心API的协作方式。
实现方案
创建两个C源文件:server.c(接收方)与client.c(发送方)。接收方先创建通道(ChannelCreate())并打印通道ID,发送方通过该通道ID建立连接(ConnectAttach())后发送消息。接收方收到消息后原样回复附加的确认文本。两端均使用标准输入输出打印关键状态,便于在终端直接观察通信过程。
完整代码
server.c — 消息接收与回复进程:
#include <stdio.h>
#include <string.h>
#include <sys/neutrino.h>
#include <process.h> // 提供 getpid()
int main(void) {
int chid, rcvid;
char msg[128];
char reply[128];
// 1. 创建消息通道
chid = ChannelCreate(0);
if (chid == -1) {
perror("ChannelCreate");
return 1;
}
printf("Server: chid=%d, pid=%d\n", chid, getpid());
fflush(stdout);
// 2. 循环等待消息(本示例只处理一次后退出)
rcvid = MsgReceive(chid, msg, sizeof(msg), NULL);
if (rcvid == -1) {
perror("MsgReceive");
return 1;
}
printf("Server: received \"%s\" from rcvid=%d\n", msg, rcvid);
// 3. 构造回复并发送
snprintf(reply, sizeof(reply), "ACK from server (chid=%d)", chid);
if (MsgReply(rcvid, 0, reply, strlen(reply) + 1) == -1) {
perror("MsgReply");
return 1;
}
printf("Server: replied \"%s\"\n", reply);
// 4. 清理
ChannelDestroy(chid);
return 0;
}
client.c — 消息发送进程:
#include <stdio.h>
#include <string.h>
#include <sys/neutrino.h>
#include <process.h>
int main(int argc, char *argv[]) {
int coid, chid, pid;
char msg[128] = "Hello from client";
char reply[128];
// 从命令行获取服务端 pid 和 chid
if (argc != 3) {
fprintf(stderr, "Usage: %s <server_pid> <server_chid>\n", argv[0]);
return 1;
}
pid = atoi(argv[1]);
chid = atoi(argv[2]);
// 1. 连接到服务端通道
coid = ConnectAttach(0, pid, chid, 0, 0);
if (coid == -1) {
perror("ConnectAttach");
return 1;
}
// 2. 发送消息并等待回复(MsgSend 自动阻塞直到收到回复)
if (MsgSend(coid, msg, strlen(msg) + 1, reply, sizeof(reply)) == -1) {
perror("MsgSend");
return 1;
}
printf("Client: sent \"%s\"\n", msg);
printf("Client: got reply \"%s\"\n", reply);
// 3. 断开连接
ConnectDetach(coid);
return 0;
}
编译与运行
在QNX目标机上(或QNX SDP的终端中)执行以下命令:
# 编译两个进程
qcc -o server server.c
qcc -o client client.c
# 先启动服务端(记录输出的 pid 和 chid)
./server
# 另开一个终端,用服务端输出的 pid 和 chid 启动客户端
./client <server_pid> <server_chid>
验证方法与通过标准
按以下步骤确认通信成功:
- 服务端终端输出包含
chid=和pid=的行,记录这两个值。 - 客户端启动后,服务端终端应显示
Server: received "Hello from client",随后显示Server: replied "ACK from server..."。 - 客户端终端应显示
Client: sent "Hello from client"和Client: got reply "ACK from server..."。 - 两端进程均正常退出(无错误信息),且服务端打印的回复内容与客户端收到的回复内容一致,即判定通过。
关键说明
MsgSend()是同步阻塞调用:发送后必须等待接收方MsgReply()才会返回,这保证了请求-响应语义。- 服务端使用
MsgReceive()的rcvid作为回复目标标识,该值由内核分配,不能跨进程传递使用。 - 消息内容以字符串形式传递,长度参数需包含结尾的
'\0'(代码中通过strlen()+1实现)。 - 若客户端指定的
pid或chid错误,ConnectAttach()会返回 -1,运行时报错即可定位。