【问题标题】:Redirect output from program A to program B's input and viceversa将程序 A 的输出重定向到程序 B 的输入,反之亦然
【发布时间】:2016-08-22 20:41:37
【问题描述】:

我知道有一种方法可以通过使用 fork 并以某种方式制作管道在 C 中进行编程(我知道有一种方法,但我不记得该怎么做)。

预期用途是将服务器的输出(我将使用 netcat 获得)连接到我自己的 C++ 程序,该程序将处理所述输出并将其返回给 netcat。我不知道如何在 C++ 中直接连接(套接字是神秘的存在),我想避免安装 boost,因为它应该在或多或少的 vanilla 系统中编译。

那么,有没有办法使用 bash 将一个程序的输出重定向到另一个程序的输入,并将第二个程序的输出重定向到 bash 中第一个程序的输入?

【问题讨论】:

  • netcat 的哪个实现?有些可以做你描述的你会在 C 中做的事情。
  • ubuntu 'netcat-openbsd' 中的那个。它确实说有另一种选择。如果它能做到你说的我会很高兴:)

标签: c++ bash input pipe output


【解决方案1】:

如果您正在使用 C 风格的服务器和客户端,那么可以使用以下基于套接字的解决方案将数据从服务器传输到客户端。

该解决方案使用popen 函数在您的主机系统上运行所需的命令,然后使用sendrecv 原语将数据传输到客户端进行套接字编程。

代码如下:

服务器:

#include "stdio.h"
#include "stdlib.h"
#include "sys/socket.h"
#include "sys/types.h"
#include "netinet/in.h"
#include "error.h"
#include "string.h"
#include "unistd.h"
#include "arpa/inet.h"

#define ERROR    -1
#define MAX_CLIENTS    2
#define MAX_DATA    1024


main(int argc, char **argv)
{
    struct sockaddr_in server;
    struct sockaddr_in client;
    int sock;
    int new,i;
    int sockaddr_len = sizeof(struct sockaddr_in);
    int data_len;
    char data[MAX_DATA];
    char temp[MAX_DATA];


    if((sock = socket(AF_INET, SOCK_STREAM, 0)) == ERROR)
    {
        perror("server socket: ");
        exit(-1);
    }

    server.sin_family = AF_INET;
    server.sin_port = htons(atoi(argv[1]));
    server.sin_addr.s_addr = INADDR_ANY;
    bzero(&server.sin_zero, 8);

    if((bind(sock, (struct sockaddr *)&server, sockaddr_len)) == ERROR)
    {
        perror("bind : ");
        exit(-1);
    }

    if((listen(sock, MAX_CLIENTS)) == ERROR)
    {
        perror("listen");
        exit(-1);
    }
    printf("\nThe TCPServer Waiting for client on port %d\n",ntohs(server.sin_port));
        fflush(stdout);

    FILE *fp;
    char path[1035];

    /* Open the command for reading. */
    fp = popen("/bin/ls /etc/", "r");

    if((new = accept(sock, (struct sockaddr *)&client, &sockaddr_len)) == ERROR)
    {
        perror("accept");
        exit(-1);
    }

    printf("New Client connected from port no %d and IP %s\n", ntohs(client.sin_port), inet_ntoa(client.sin_addr));

    data_len = 1;

    int path_len; 
    while (fgets(path, sizeof(path)-1, fp) != NULL) {
        path_len = strlen(path);
        send(new, path, path_len, 0);    
    }


    printf("Client disconnected\n");

    close(new);

    close(sock);


}

客户:

#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "unistd.h"
#include "sys/socket.h"
#include "sys/types.h"
#include "netinet/in.h"
#include "strings.h"
#include "arpa/inet.h"


#define BUFFER    1024


main(int argc, char **argv)
{
    struct sockaddr_in serv;
    int sock;
    char in[BUFFER];
    char out[BUFFER];
    int len;


    if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket");
        exit(-1);
    }

    serv.sin_family = AF_INET;
    serv.sin_port = htons(atoi(argv[2]));
    serv.sin_addr.s_addr = inet_addr(argv[1]);
    bzero(&serv.sin_zero, 8);

    printf("\nThe TCPclient %d\n",ntohs(serv.sin_port));
        fflush(stdout);


    if((connect(sock, (struct sockaddr *)&serv, sizeof(struct sockaddr_in))) == -1)
    {
        perror("connect");
        exit(-1);
    }

    len = 1;
    while(len != 0) {
        len = recv(sock, out, BUFFER, 0);
        out[len] = '\0';
        printf("Output: %s\n", out);
    }

    close(sock);


}

服务器代码将端口号作为命令行参数,客户端将 ip 地址(本地主机为 127.0.0.1)和端口号作为命令行参数。

即使您使用其他语言运行服务器,您也可以简单地使用该服务器的套接字原语将数据发送到客户端文件。

注意:代码是用 C 编写的,使用 C++ 编译时可能会产生一些错误。请检查编译错误。

【讨论】:

    【解决方案2】:

    给定一个 netcat 实现,你已经拥有了你需要的东西。假设您的客户端名为/path/to/client,您想在端口 1234 上连接到service.example.com

    要么你的 netcat 就像来自 nmap 的 ncat,那么你可以这样做:

    ncat -c ``/path/to/client`` service.example.com 1234
    

    如果你的 netcat 更简约,你必须使用管道:

    mkdir pipes
    cd pipes
    mkfifo reverse_pipe
    /path/to/client < reverse_pipe | nc service.example.com 1234 > reverse_pipe
    

    mkfifo 在文件系统中创建命名管道。它看起来像一个文件,但实际上不是(如果您使用ls -l 查看,您会注意到它的模式以p 开头,而不是像通常的文件那样以- 开头)。这就像foo | bar 所做的一样,但它有一个文件名并且不被任何进程打开。

    通过将此作为输入/输出传递给进程,您可以手动连接两个命令(即,无需使用诸如 | 之类的 shell 魔法)。写入管道的数据不存储在文件系统中,但可用于从管道读取的进程。写入的数据只能读取一次。它的工作原理与 shell 中的管道完全一样,只是它在文件系统中有一个名称。

    【讨论】:

    • 默认的 netcat 没有 '-c' 选项。传统的虽然。而mkfifo方法我不是很懂。我不知道那个命令,但它似乎只是创建一个文件?
    • @MJGalram 我添加了几行关于mkfifo
    • 我最终使用了命名管道和 tee 的组合(在屏幕上查看输出)
    猜你喜欢
    • 2016-04-27
    • 1970-01-01
    • 1970-01-01
    • 2014-12-02
    • 1970-01-01
    • 2021-01-16
    • 1970-01-01
    • 1970-01-01
    • 2020-10-24
    相关资源
    最近更新 更多