使用pipe进行进程间通讯

Publish: September 23, 2016 Category: C/C++ No Comments

    使用pipe进行进程间通讯,pipe只能在共同血缘(父子进程)进程中使用。

一、父子进程间通讯:

/*
 * 双向管道流模式: 父子进程互相读写
 * 
 *    --------      ---------------     --------
 *   | 父进程  |    |    UNIX 内核  |    | 子进程  |
 *   |        |    |===============|    |        |
 *   | pfd1[1]|--->|输入  管道I  输出|--->| pfd1[0]|
 *   |        |    |===============|    |        |
 *   | pfd2[0]|<---|输出  管道II 输入|<---| pfd2[1]|
 *   |        |    |               |    |        |
 *    --------      ---------------      --------
 *    
 */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
    int pfd1[2], pfd2[2];
    pid_t pid;
    if (pipe(pfd1) < 0) {
        fprintf(stderr, "pipe fail:%s\n", strerror(errno));
        exit(0);
    }
    if (pipe(pfd2) < 0) {
        fprintf(stderr, "pipe fail:%s\n", strerror(errno));
        exit(0);
    }
    if ((pid = fork()) < 0) {
        fprintf(stderr, "fork fail:%s\n", strerror(errno));
        exit(0);
    }
    if (pid == 0) {
        // ------ 子进程 ------
        close(pfd1[1]);
        close(pfd2[0]);
        char buf[1024] = {0};
        int r = 0;
        while (r = read(pfd1[0], buf, sizeof(buf))) {
            if (r > 0) {
                printf("  [child_%ld]:Read %d:%s", getpid(), r, buf);
                if (strcasecmp(buf, "quit\n") == 0) {
                    r = snprintf(buf, sizeof(buf), "Bye Bye.\n");
                    r = write(pfd2[1], buf, r);
                    printf("  [child_%ld]: %ld:%s", getpid(), r, buf);
                    return 0;
                }
                memset(buf, 0, sizeof(buf));
                r = snprintf(buf, sizeof(buf), "250 OK\n");
                r = write(pfd2[1], buf, r);
                printf("  [child_%ld]:Write %ld:%s", getpid(), r, buf);
                memset(buf, 0, sizeof(buf));
            }
        }
        return 0;
    }
    // ------ 父进程 ------
    char buf[1024] = {0};
    int r = 0;
    close(pfd1[0]);
    close(pfd2[1]);
    while (fgets(buf, sizeof(buf), stdin) != NULL) {
        printf("[parent_%ld]:Read %d:%s", getpid(), strlen(buf), buf);
        r = write(pfd1[1], buf, strlen(buf));
        printf("[parent_%ld]:Write %d bytes, Succ\n", getpid(), r);
        memset(buf, 0, sizeof(buf));
        r = read(pfd2[0], buf, sizeof(buf));
        printf("[parent_%ld]:Read: %d:%s", getpid(), r, buf);
        if (strcasecmp(buf, "Bye Bye.\n") == 0) {
            printf("[parent_%ld]:Read: %d:%s", getpid(), r, buf);
            return 0;
        }
        memset(buf, 0, sizeof(buf));
    }
    return 0;
}


二、连接标准I/O的管道流模式:  子进程使用标准I/O文件描述符进行通讯

    pipe_parent.c:

/*
 * 连接标准I/O的管道流模式: 父子进程互相读写
 * 
 *    --------            -----------------          ---------------
 *   | 父进程 |          |    UNIX 内核    |        | 子进程        |
 *   |        |          |=================|        |               |
 *   | pfd1[1]| -------> |输入  管道I  输出| ------>| 0 <==>pfd1[0] |
 *   |        |          |=================|        |               |
 *   | pfd2[0]| <------- |输出  管道II 输入| <------| 1 <==>pfd2[1] |
 *   |        |          |                 |        |               |
 *    --------            -----------------          ---------------
 *    
 */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
char *(pipe_child[]) = { "./pipe_child", 0};
int main(int argc, char **argv)
{
    int pfd1[2], pfd2[2];
    pid_t pid;
    if (pipe(pfd1) < 0) {
        fprintf(stderr, "pipe fail:%s\n", strerror(errno));
        exit(0);
    }
    if (pipe(pfd2) < 0) {
        fprintf(stderr, "pipe fail:%s\n", strerror(errno));
        exit(0);
    }
    if ((pid = fork()) < 0) {
        fprintf(stderr, "fork fail:%s\n", strerror(errno));
        exit(0);
    }
    if (pid == 0) {
        // ------ 子进程 ------
        if (dup2(pfd1[0], 0) < 0) {
        fprintf(stderr, "child dup2 fail:%s\n", strerror(errno));
        _exit(1);
        }
        if (dup2(pfd2[1], 1) < 0) {
            fprintf(stderr, "child dup2 fail:%s\n", strerror(errno));
            _exit(1);
        }
        close(pfd1[1]);
        close(pfd2[0]);
        int ret = execvp(*pipe_child, pipe_child);
        if (ret < 0) {
            fprintf(stderr, "child execvp:%s fail:%s\n", pipe_child, strerror(errno));
            _exit(1);
        }
        return 0;
    }
    // ------ 父进程 ------
    close(pfd1[0]);
    close(pfd2[1]);
    char buf[1024] = {0};
    int r = 0;
    while (fgets(buf, sizeof(buf), stdin) != NULL) {
        printf("[parent_%ld]:Read %d:%s", getpid(), strlen(buf), buf);
        r = write(pfd1[1], buf, strlen(buf));
        printf("[parent_%ld]:Write %d bytes, Succ\n", getpid(), r);
        memset(buf, 0, sizeof(buf));
        r = read(pfd2[0], buf, sizeof(buf));
        printf("[parent_%ld]:Read: %d:%s", getpid(), r, buf);
        if (strcasecmp(buf, "Bye Bye.\n") == 0) {
            printf("[parent_%ld]:Read: %d:%s", getpid(), r, buf);
            return 0;
        }
        memset(buf, 0, sizeof(buf));
    }
    return 0;
}


    pipe_child.c:

/*
 * 连接标准I/O的管道流模式: 父子进程互相读写
 * 
 *    --------            -----------------          ---------------
 *   | 父进程 |          |    UNIX 内核    |        | 子进程        |
 *   |        |          |=================|        |               |
 *   | pfd1[1]| -------> |输入  管道I  输出| ------>| 0 <==>pfd1[0] |
 *   |        |          |=================|        |               |
 *   | pfd2[0]| <------- |输出  管道II 输入| <------| 1 <==>pfd2[1] |
 *   |        |          |                 |        |               |
 *    --------            -----------------          ---------------
 *    
 */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
    char buf[1024] = {0};
    int r = 0;
    while (r = read(0, buf, sizeof(buf))) {
        if (r > 0) {
            fprintf(stderr, "  [child_%ld]:Read %d:%s", getpid(), r, buf);
            if (strcasecmp(buf, "quit\n") == 0) {
                r = snprintf(buf, sizeof(buf), "Bye Bye.\n");
                r = write(1, buf, r);
                fprintf(stderr, "  [child_%ld]: %ld:%s", getpid(), r, buf);
                return 0;
            }
            memset(buf, 0, sizeof(buf));
            r = snprintf(buf, sizeof(buf), "250 OK\n");
            r = write(1, buf, r);
            fprintf(stderr, "  [child_%ld]:Write %ld:%s", getpid(), r, buf);
            memset(buf, 0, sizeof(buf));
        }
    }
    return 0;
}



正确使用 realloc 方法

Publish: September 5, 2016 Category: C/C++ No Comments

1. realloc第一种行为引发的bug

void *ptr = realloc(ptr, new_size);
if (!ptr) {
    错误处理
}

这里就引出了一个内存泄露的问题,当realloc分配失败的时候,会返回NULL。但是参数中的ptr的内存是没有被释放的。如果直接将realloc的返回值赋给ptr。那么当申请内存失败时,就会造成ptr原来指向的内存丢失,造成泄露。


2. 正确的处理应该是这样

void *new_ptr = realloc(ptr, new_size);
if (!new_ptr) {
    错误处理。
}
ptr = new_ptr


C 遍历目录文件

Publish: September 2, 2016 Category: C/C++ No Comments

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>


int trave_dir(char *path)
{
    DIR *pdir;
    struct dirent *pent;
    struct stat sb; 
    if ((pdir = opendir(path)) == NULL) {
        return -1; 
    }   
    
    while ((pent = readdir(pdir)) != NULL) {
        // 去掉(. .. 隐藏文件)
        if (strncmp(pent->d_name, ".", 1) == 0) continue;
    
        char new_path[BUF_SIZE] = {0};
        snprintf(new_path, sizeof(new_path), "%s/%s", path, pent->d_name);
        printf("%s\n", new_path);
        if (stat(new_path, &sb) >= 0 && S_ISDIR(sb.st_mode)) {
            trave_dir(new_path);
        }   
    }   
    closedir(pdir);
    return 0;
}


int main(int argc, char **argv)
{
    trave_dir(argv[1]);

    return 0;
}


编译运行:

# gcc -g -o test test.c
# ./test .