C中的进程间通信

时间:2016-05-30 00:34:25

标签: c process pipe ipc

我正在使用管道对IPC进行练习。协议如下:

  1. client(child)从stdin
  2. 读取文件名
  3. 客户端通过管道将文件名发送到服务器
  4. server(parent)从管道中读取文件名
  5. 服务器获取有关文件的信息(stat sys call)
  6. 服务器通过管道向客户端发送文件信息。
  7. 客户端从管道读取文件信息并输出到stdout
  8. 我在最后的步骤中遇到问题,我不知道如何正确发送这些信息。目前客户端的输出是垃圾。这是代码:

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <string.h>
    
    #define BUFSIZE 1024
    
    int main()
    {
        int fd1[2], fd2[2], pid, n;
        char buf[BUFSIZE];
        pipe(fd1);
        pipe(fd2);
        if ((pid = fork()) == 0)
        {
            close(fd1[0]);
            close(fd2[1]);
            read(STDIN_FILENO, buf, BUFSIZE); // 1. client(child) reads file name from stdin
            int len = strlen(buf);
            buf[len - 1] = '\0';
            write(fd1[1], buf, len); // 2. client sends file name over pipe to server
            while ((n = read(fd2[0], buf, BUFSIZE)) > 0)
            {
                write (STDOUT_FILENO, buf, n); // 6. client reads file info from pipe and outputs to stdout
            }
        }
        else
        {
            struct stat st;
            close(fd1[1]);
            close(fd2[0]);
            read(fd1[0], buf, BUFSIZE); // 3. server (parent) reads file name from pipe
            stat(buf, &st); // 4. server obtains information about the file (stat sys call)
            write(fd2[1], (void *)st.st_size, sizeof(st.st_size)); // 5. server file information over pipe to client.
            write(fd2[1], (void *)st.st_atime, sizeof(st.st_atime));
        }
        return 0;
    }
    

    更新

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <string.h>
    
    #define BUFSIZE 1024
    
    int main()
    {
        int fd1[2], fd2[2], pid;
        size_t n;
        char buf[BUFSIZE];
        pipe(fd1);
        pipe(fd2);
        if ((pid = fork()) == 0)
        {
            close(fd1[0]);
            close(fd2[1]);
            n = read(STDIN_FILENO, buf, BUFSIZE - 1); // 1. client(child) reads file name from stdin
            buf[n] = '\0';
            write(fd1[1], buf, n); // 2. client sends file name over pipe to server
            while ((n = read(fd2[0], buf, BUFSIZE)) > 0)
            {
                if ((write (STDOUT_FILENO, buf, n)) != n) // 6. client reads file info from pipe and outputs to stdout
                {
                    perror("client: write error\n");
                }
            }
        }
        else
        {
            struct stat st;
            close(fd1[1]);
            close(fd2[0]);
            read(fd1[0], buf, BUFSIZE); // 3. server (parent) reads file name from pipe
            stat(buf, &st); // 4. server obtains information about the file (stat sys call)
            if (write(fd2[1], (void *)st.st_size, sizeof(st.st_size)) != sizeof(st.st_size)) // 5. server sends file information over pipe to client
            {
                perror("server: write error\n");
            } 
            if (write(fd2[1], (void *)st.st_atime, sizeof(st.st_atime)) != sizeof (st.st_atime))
            {
                perror("server: write error\n");
            }
        }
        return 0;
    }
    

1 个答案:

答案 0 :(得分:0)

您无法在此处使用strlen()。您应该使用read()的返回值。

read()之后buf中的数据只是一个字节序列,如果在序列末尾添加'\0'字节,它可能会成为一个字符串。由于它不存在,因此调用strlen()会调用未定义的行为,因此在此之后您所做的事情并不重要,它将无法按预期运行。

strlen()可以被认为是

size_t 
strlen(const char *const string)
{
    size_t length;
    length = 0;
    while (string[length] != '\0')
        ++length;
    return length;
}

你应该避免像

这样的事情的一个原因
for (size_t i = 0 ; i < strlen(string) ; ++i) ...

特别是因为您可以使用类似上面strlen()实现中的循环。

使用来自read()的返回值

ssize_t read_length;
read_length = read(STDIN_FILENO, buf, sizeof(buf) - 1);

如果你想让它成为一个有效的字符串,你可以把它传递给任何str*函数,只需

buf[read_length] = '\0';
不要忘记检查错误read_length != -1