尝试将数据从子进程服务器传递到其父进程

时间:2011-11-20 07:03:21

标签: c unix pipe

我正在为我的分布式系统类工作。我是C.S.的硕士生,但我在编程方面的专长是.NET,我正在开发一个项目,需要一些相当普遍的Unix知识,这让我很沮丧。

该任务正在实施刷新通道协议API。所以我正在编写一个小型函数库,其他应用程序可以使用它来实现刷新通道通信。我进行了设置,以便在调用init函数时,它会将子进程作为传入消息的服务器。子进程通过管道将传入数据发送给父进程与父进程通信。

如果一次发送和接收一条消息,则此工作正常;如,

发送 - >接收 - >发送 - >接收 - >等

但是,如果在进行任何接收之前发送了多条消息;如,

发送 - >发送 - >发送 - >接收

然后它搞砸了。具体来说,第一条消息被正确接收,但当我去接收第二条消息时,程序挂起并需要被杀死。我已经做了大量的在线搜索工作,并且已经花了好几个小时,但没有取得多大进展。

整个程序太大而无法在此显示,但这里是最相关的部分。这是我让服务器前进和接收消息的部分。注意这一行

写(fd [1],缓冲区,(strlen(缓冲区)+1));

- 我认为这是一个很好的候选人,可以成为问题的根源,但不知道该怎么做。 (尝试过fwrite(),但根本没用。)

    fd = malloc(2 * sizeof(int));
    int nbytes;
    if (pipe(fd) < 0) {
        perror("Could not create pipe");
        return -1;
    }

    pID = fork();

    if (pID < 0) {
        perror("Failed to fork");
        return -1;
    } else if (pID == 0) { // child
        close(fd[0]);  // close input side of pipe
        int cc;
        int fsize;
        struct sockaddr_in from;
        int serials[500];
        int i;
        for (i = 0; i < 500; i++) serials[i] = 0;

        char buffer[2048];

        while (1) {
            fsize = sizeof(from);
            cc = recvfrom(socketNo, buffer, 2048, 0, (struct sockaddr*)&from, &fsize);
            if (cc < 0) perror("Receive error");
            datagram data = decodeDatagram(buffer);
            if (serials[data.serial] == 0) {
                write(fd[1], buffer, (strlen(buffer)+1));
                serials[data.serial] = 1;
            }
        }
    } else { // parent
        close(fd[1]);  // close output side of pipe
        return 0;
    }

(“serials”数组用于不转发重复消息,因为消息被多次发送以提高可靠性。我知道这个数组的固定大小不是好习惯,但是这个分配的测试不会发送很多消息,所以在这种情况下没问题。)

接收函数的开头如下所示:

int fRecv(int* id, char* buf, int nbytes) {

    checkDatagramTable(*id);

    char* tbuf = malloc((nbytes + 9) * sizeof(char));
    int rbytes = read(fd[0], tbuf, nbytes + 9);

“+9”用于容纳与要发送的消息一起打包的附加信息,用于刷新通道排序。这也是一个相当粗略的区域,但是分配更多的空间来确保这个问题没有帮助。

我知道这里有很多无关紧要的东西,对其他函数等的引用。但问题肯定在于我如何管理数据,因此我的问题的根源应该在某处。

预先感谢您的协助;真的很感激。

1 个答案:

答案 0 :(得分:1)

这看起来很可疑。 (数据包中的内容是什么?它们可以是二进制的)数据报的typedefinition在哪里?

fsize = sizeof(from);
        cc = recvfrom(socketNo, buffer, 2048, 0, (struct sockaddr*)&from, &fsize);
        if (cc < 0) perror("Receive error");
        datagram data = decodeDatagram(buffer);
        if (serials[data.serial] == 0) {
            write(fd[1], buffer, (strlen(buffer)+1)); // <-- ????
            serials[data.serial] = 1;
        }

我试着改为:

            write(fd[1], buffer, cc);

更新:

如果消息未终止,则必须明确终止:

    (if cc == 2048) cc -= 1; 
    buffer [cc] = '\0'; // <<--
    datagram data = decodedatagram(buffer);
    ...

此外,建议使用“sizeof buffer”而不是“2048”。

UPDATE2: 您可以通过以下方式测试数据包中的字符串是否真正以null结尾:

        unsigned pos;
        cc = recvfrom(socketNo, buffer, 2048, 0, (struct sockaddr*)&from, &fsize);
        if (cc < 0) perror("Receive error");
        for pos=0; pos < cc; pos++) {
             if (buff[pos] == 0) break;
             }
        switch (cc-pos) {
        case 0: fprintf (stderr, "No nul byte found in packet: I lose!\n" ); break;
        default: fprintf (stderr, "Spurious nul byte found in the middle of packet\n" );
        case 1: break;
             }

        datagram data = decodeDatagram(buffer);
        if (serials[data.serial] == 0) {
            write(fd[1], buffer, cc);
            serials[data.serial] = 1;
        }