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. 服务启动验证:终端1输出Server: channel created, chid=..., name=/tmp/svc_channel,且进程不退出。
  2. 功能验证:终端2执行./client 1 "Hello QNX",预期输出Response: status=0, data="Hello QNX";执行./client 2 "hello qnx",预期输出Response: status=0, data="HELLO QNX"。
  3. 异常路径验证:执行./client 3 "test",预期输出Response: status=-1, data="unsupported type"。
  4. 连接失败验证:不启动server直接运行client,预期输出name_open错误信息及提示Is server running?。

以上预期输出均由代码逻辑直接推出,满足条件即判定服务进程消息传递功能正常。