首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >IPC使用管道

IPC使用管道
EN

Code Review用户
提问于 2016-10-24 23:43:09
回答 2查看 289关注 0票数 2

我用叉子和烟斗模拟了呼叫者和接收者之间的对话。父进程是接收方,子进程是调用方。每条消息都以换行符结束。

这个程序似乎运行正常。我还需要照顾其他的情况吗?

代码语言:javascript
复制
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#include <unistd.h>

#define BUF_LEN 512
#define READ_END 0
#define WRITE_END 1

int main()
{
    int fd[2];
    if (pipe(fd) == -1) {
        fprintf(stderr, "Pipe failed");
        return 1; 
    }
    pid_t pid = fork();

    if (pid < 0) {
        fprintf(stderr, "Fork failed");
        return 1;
    } 

    // the parent process is the receiver
    if (pid > 0) {
        close(fd[WRITE_END]);
        char buffer[BUF_LEN + 1] = "";
        bool end_call = false;
        do {
            // strcpy(buffer, "");
            if (read(fd[READ_END], buffer, sizeof buffer) != 0) {
                // char *start = buffer;
                char msg[BUF_LEN + 1] = "";
                char *end = buffer;
                int i = strlen(msg);
                while (*end) {
                    msg[i++] = *(end++);
                    msg[i] = '\0';
                    if (msg[strlen(msg) - 1] == '\n') {
                        printf("Receiver: Received %s", msg);
                        if (!strcmp(msg, "Bye!\n")) {
                            end_call = true;
                        }
                        strcpy(msg, "");
                        i = strlen(msg);
                    }
                }
                // if (strcmp(buffer, "")) {
                //  printf("Received %s", buffer);
                // }
            }
        } while (!end_call);
        close(fd[READ_END]);
    } else {
        close(fd[READ_END]);
        // const char *msg = "Hello";
        char buffer[BUF_LEN + 1] = "";
        bool end_call = false;
        printf("Caller: Enter messages to be sent to the receiver."
                "(\"Bye!\" to end call)\n");
        do {
            // printf("Caller: ");
            fgets(buffer, sizeof buffer, stdin);
            if (!strcmp(buffer, "Bye!\n")) {
                end_call = true;
            }
            // printf("Sent %s\n", buffer);
            write(fd[WRITE_END], buffer, strlen(buffer) + 1);
        } while (!end_call);
        close(fd[WRITE_END]);
    }
    return 0;
}
EN

回答 2

Code Review用户

回答已采纳

发布于 2016-10-25 03:12:27

这么多对strlen()

的调用

让我们在这个代码块中计算对strlen()的调用:

if (read(fd[READ\_END], buffer, sizeof buffer) != 0) { // char \*start = buffer; char msg[BUF\_LEN + 1] = ""; char \*end = buffer; int i = strlen(msg); while (\*end) { msg[i++] = \*(end++); msg[i] = '\0'; if (msg[strlen(msg) - 1] == '\n') { printf("Receiver: Received %s", msg); if (!strcmp(msg, "Bye!\n")) { end\_call = true; } strcpy(msg, ""); i = strlen(msg); } } // if (strcmp(buffer, "")) { // printf("Received %s", buffer); // } }

  1. 第一个调用在开始时,其中msg仍然是空的。因此,这一行可以用i = 0代替。
  2. 第二个调用是检查换行符的最后一个字符。但是您只是在msg[i-1]添加了这个字符,所以不需要调用strlen()
  3. 第三个调用发生在您将msg设置为""之后。所以你知道这里的长度是零。您也不需要调用strcpy()仅仅是为了清除msg

修改后的代码为零调用strlen()strcpy(),如下所示:

代码语言:javascript
复制
        if (read(fd[READ_END], buffer, sizeof buffer) != 0) {
            char msg[BUF_LEN + 1] = "";
            char *end = buffer;
            int i = 0;
            while (*end) {
                msg[i++] = *(end++);
                msg[i] = '\0';
                if (msg[i - 1] == '\n') {
                    printf("Receiver: Received %s", msg);
                    if (!strcmp(msg, "Bye!\n")) {
                        end_call = true;
                    }
                    msg[0] = '\0';
                    i = 0;
                }
            }
        }

电位缓冲区溢出

在实际程序中,由于您同时控制客户端和服务器,因此没有实际的缓冲区溢出。但是,如果只查看服务器部分,就会发现一个潜在的问题:

char buffer[BUF\_LEN + 1] = ""; if (read(fd[READ\_END], buffer, sizeof buffer) != 0) {

在这里,使用read调用sizeof buffer,这意味着它可以填充整个缓冲区,而不需要终止空字符。

然后,使用以下内容迭代缓冲区:

char \*end = buffer; while (\*end) {

这意味着,如果没有空终止字符,您将读取缓冲区的末尾。

看起来,您将缓冲区大小调整为BUF_LEN + 1是有原因的(为一个确定的空字符留出空间),所以您应该只调用一个长度较短的read()

代码语言:javascript
复制
    if (read(fd[READ_END], buffer, sizeof(buffer)-1) != 0) {
票数 2
EN

Code Review用户

发布于 2016-10-25 03:19:18

  • 每当您想要放置//这样的注释时,父进程就是接收方将注释的功能委托给函数: if (pid > 0) {接收器(.);}并删除注释。代码变成了自我记录。
  • 接收器的逻辑有点奇怪。对于错误,read返回-1,一旦发生错误,它很可能会继续返回-1,使接收器陷入无限循环。我建议int rc;while ((rc =read(.)> 0) {do_receiver_logic(.);} if (rc == 0) { handle_peer_close();}handle_read_error()}您可能希望特别注意瞬态错误,但我宁愿尝试重新连接。
  • 发送者逻辑依赖于消息生成器的良好行为。如果不是说"Bye"关闭了流,那么发送方注定要永远重复发送最后一个字符串。至少,测试fgets返回的不是NULL
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/145153

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档