2. QNX侧创建基础服务进程
任务目标
在QNX侧创建一个独立运行的服务进程,通过QNX原生消息传递接口(MsgSend/MsgReceive)接收客户端请求并返回响应,建立最基本的进程间通信(IPC)闭环。
环境与依赖
- QNX SDP 7.0或以上版本(含
qcc编译器) - 目标机为QNX Neutrino实时操作系统
- 无需额外第三方库,仅使用系统头文件
<sys/neutrino.h>、<sys/netmgr.h>
实现方案
服务进程创建通道(channel),在已知路径/tmp/svc_channel上注册名字,使客户端可通过name_open连接。服务端循环接收消息,根据消息类型返回处理结果。客户端作为独立进程发送请求并打印响应,用于验证服务进程功能。
关键完整代码
以下代码包含服务端与客户端两个源文件,分别编译为两个可执行文件。
// server.c — QNX服务进程
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/neutrino.h>
#include <sys/netmgr.h>
#include <process.h>
#define CHANNEL_NAME "/tmp/svc_channel"
#define MAX_MSG_LEN 256
typedef struct {
int type; // 消息类型:1=echo, 2=upper
char data[MAX_MSG_LEN];
} request_t;
typedef struct {
int status; // 0=成功,非0=失败
char data[MAX_MSG_LEN];
} response_t;
int main(void) {
int chid, rcvid;
request_t req;
response_t resp;
// 创建通道
chid = ChannelCreate(0);
if (chid == -1) {
perror("ChannelCreate");
return 1;
}
// 注册通道名称,供客户端name_open使用
if (name_attach(chid, CHANNEL_NAME, 0) == -1) {
perror("name_attach");
return 1;
}
printf("Server: channel created, chid=%d, name=%s\n", chid, CHANNEL_NAME);
fflush(stdout);
// 服务循环
while (1) {
rcvid = MsgReceive(chid, &req, sizeof(req), NULL);
if (rcvid == -1) {
perror("MsgReceive");
continue;
}
// 处理请求
memset(&resp, 0, sizeof(resp));
if (req.type == 1) { // echo
resp.status = 0;
strcpy(resp.data, req.data);
} else if (req.type == 2) { // 转大写
resp.status = 0;
for (int i = 0; req.data[i] && i < MAX_MSG_LEN - 1; i++) {
char c = req.data[i];
resp.data[i] = (c >= 'a' && c <= 'z') ? c - 32 : c;
}
} else {
resp.status = -1;
strcpy(resp.data, "unsupported type");
}
// 发送响应
if (MsgReply(rcvid, 0, &resp, sizeof(resp)) == -1) {
perror("MsgReply");
}
}
return 0;
}
// client.c — 测试客户端
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/neutrino.h>
#include <sys/netmgr.h>
#include <process.h>
#define CHANNEL_NAME "/tmp/svc_channel"
#define MAX_MSG_LEN 256
typedef struct {
int type;
char data[MAX_MSG_LEN];
} request_t;
typedef struct {
int status;
char data[MAX_MSG_LEN];
} response_t;
int main(int argc, char **argv) {
int coid;
request_t req;
response_t resp;
if (argc < 3) {
fprintf(stderr, "Usage: %s <1|2> <string>\n", argv[0]);
fprintf(stderr, " 1 = echo, 2 = uppercase\n");
return 1;
}
// 连接服务端
coid = name_open(CHANNEL_NAME, 0);
if (coid == -1) {
perror("name_open");
fprintf(stderr, "Is server running?\n");
return 1;
}
// 构造请求
req.type = atoi(argv[1]);
strncpy(req.data, argv[2], MAX_MSG_LEN - 1);
req.data[MAX_MSG_LEN - 1] = '\0';
// 发送并等待响应
if (MsgSend(coid, &req, sizeof(req), &resp, sizeof(resp)) == -1) {
perror("MsgSend");
name_close(coid);
return 1;
}
// 打印结果
printf("Response: status=%d, data=\"%s\"\n", resp.status, resp.data);
name_close(coid);
return 0;
}
编译与运行
# 在QNX主机环境编译
qcc -o server server.c
qcc -o client client.c
# 将两个可执行文件部署到目标机后,在目标机shell执行:
# 终端1:启动服务
./server
# 终端2:调用客户端(echo模式)
./client 1 "Hello QNX"
# 终端2:调用客户端(大写转换模式)
./client 2 "hello qnx"
验证方法与通过标准
- 服务启动验证:终端1输出
Server: channel created, chid=..., name=/tmp/svc_channel,且进程不退出。 - 功能验证:终端2执行
./client 1 "Hello QNX",预期输出Response: status=0, data="Hello QNX";执行./client 2 "hello qnx",预期输出Response: status=0, data="HELLO QNX"。 - 异常路径验证:执行
./client 3 "test",预期输出Response: status=-1, data="unsupported type"。 - 连接失败验证:不启动server直接运行client,预期输出
name_open错误信息及提示Is server running?。
以上预期输出均由代码逻辑直接推出,满足条件即判定服务进程消息传递功能正常。