【问题标题】:Redirecting stdout to socket in client-server situation在客户端-服务器情况下将标准输出重定向到套接字
【发布时间】:2015-06-22 22:42:36
【问题描述】:

我是这个论坛的新手,如果我的问题没有被正确提出,我很抱歉。我会尽量说清楚。

我正在尝试在 Linux 中编写两个程序(client.c 和 server.c,使用 TCP 套接字),其行为如下:

  • 客户端向服务器发送消息,其中包含要由服务器运行的命令(ls、mkdir 等)。

  • 服务器运行这些命令,并将程序输出(stdout)发送回客户端。

  • 客户端打印收到的程序输出。

到目前为止,我有这个:

server.c:

/*After creating socket with socket(), binding to address and port, 
putting in listening mode and accepting connection*/
dup2(sock_client,1);    //redirect stdout
while(1){
    recv(sock_client,buf,MAX_MSG_LENGTH,0);
    /*If the message recieved was END_STRING, exit this loop*/
    if (strncmp(buf, END_STRING, MAX_MSG_LENGTH) == 0)
        break;
    system(buf);
}

client.c:

/*After creating socket and connecting*/
while(fgets(buf,MAX_MSG_LENGTH,stdin)){
    send(sock,buf,MAX_MSG_LENGTH,0);
    if (!strncmp(buf,END_STRING,MAX_MSG_LENGTH)){
            /*If the message recieved was END_STRING, exit this loop*/
            break;
    }
    read(sock,buf,MAX_MSG_LENGTH);  //read stdout from program 
    printf("%s\n",buf);
}

我的问题是,如果一个命令的输出很长,在显示下一个命令的输出时会留下一些“垃圾”,所以我想知道是否有办法刷新套接字(显然不是,基于我的谷歌研究),或者可能以其他方式完成预期的服务器-客户端行为。

谢谢!

编辑:

好的,我已经完成了客​​户端。代码如下:

client.c:

/* After creating socket and connecting*/
while(fgets(buf,MAX_MSG_LENGTH,stdin)){
    send(sock,buf,MAX_MSG_LENGTH,0);
    if (!strncmp(buf,END_STRING,MAX_MSG_LENGTH)){
        /*If the message recieved was END_STRING, exit this loop*/
        break;
    }
    while(1){
        read_size = read(sock,buf,MAX_MSG_LENGTH);
        /*Print read_size characters from buf*/
        printf("%.*s\n", read_size, buf);
        if (read_size < MAX_MSG_LENGTH){
            /*Keep on reading until read_size < MAX_MSG_LENGTH, then exit this loop*/
            break;
        }
    }
    /*Clear buffer, just in case*/
    for (i = 0; i < MAX_MSG_LENGTH; i++){
        buf[i] = 0;
    }

就像注释一样,如果发送到服务器的命令没有任何标准输出(例如,mkdir new_directory),此程序将无法正常工作,因为在这种情况下,read() 将离开客户端永久阻塞,导致服务器永远不会收到下一个要运行的命令或END_STRING 消息从客户端离开程序。您可能可以通过使用非阻塞套接字并使用select() 从套接字读取来解决此问题,就像 synther 建议的那样。此外,在服务器中,在system(buf); 行之后,您应该添加fflush(0),这将刷新所有缓冲区(包括套接字,如果客户端发送的命令输出非常短,这可能很有用)。

非常感谢!

【问题讨论】:

  • 首先,服务器将输出发回哪里?可能是客户端没有消耗服务器发送的所有数据。调用 read 直到它返回一个小于 MAX_MSG_LENGTH 的值。
  • @SelçukCihan 更好的是,调用read() 直到它表明没有更多的数据要读取,或者在协议中构建这样的指标,因为,特别是对于网络套接字,读取的数据少于之前的数据请求是相当正常的,并不表示数据结束...

标签: c linux sockets stdout dup2


【解决方案1】:

感谢您的回答!

我尝试将此添加到我的 client.c 代码中:

/*After creating socket and connecting*/
while(fgets(buf,MAX_MSG_LENGTH,stdin)){
    /*Send command to server*/
    send(sock,buf,MAX_MSG_LENGTH,0);
    if (!strncmp(buf,END_STRING,MAX_MSG_LENGTH)){
        /*If the message recieved was END_STRING, exit this loop*/
        break;
    }
    while(1){
        read_size = read(sock,buf,MAX_MSG_LENGTH);  //read stdout from program 
        printf("%.*s\n", read_size, buf);
        if (read_size < MAX_MSG_LENGTH){
            /*Exit this loop when reading less that MAX_MSG_LENGTH*/    
            break;
        }
    }
    /*Clear the 'buf' array. I don't know if this is really necessary*/
    for (i = 0; i < MAX_MSG_LENGTH; i++){
        buf[i] = 0;
    }
}

现在,在每个命令之后,客户端只打印发送的最后一个命令的输出。如果此解决方案正确,我将对其进行更彻底的测试并编辑我的原始帖子,非常感谢!

【讨论】:

    【解决方案2】:

    也许,当您的命令输出超过MAX_MSG_LENGTH 时,您会在客户端收到“垃圾”。 read(sock,buf,MAX_MSG_LENGTH); 仅从套接字读取 MAX_MSG_LENGTH 字节,当您从下一个命令中排除它时,下一次读取套接字中的剩余字符。

    您可以在客户端中以多种方式修复它。

    1. read 返回实际读取的字节数。您可以将其与MAX_MSG_LENGTH 进行比较,然后决定是否再读一次。但是,如果您的实际数据恰好是 MAX_MSG_LENGTH 字节,那么您决定再次读取,并且 read 会阻止等待的数据,而此时不可用(stdin 也会阻止,用户无法发送新命令)。

    2. 使用非阻塞套接字修复1 中的问题。 read 将在没有可用数据时立即返回。

    3. 将命令结束标记添加到服务器的输出中,客户端将知道何时停止读取并切换到stdin 读取。

    4. 使用select() 机制“同时”读取套接字和用户输入。它允许从多个文件描述符(socket 和stdio)中读取任何一个可用的数据。

    此外,您对用户命令和服务器响应使用相同的缓冲区。通常,用户命令比服务器输出短,buf 可能包含最后服务器输出的部分内容。然后你将这个用户命令和最后一个服务器输出的混合发送到服务器。

    并且,如上所述,read 返回实际读取的字节数。您应该打印从buf 准确接收的字节数,而不是所有数据。

        int ret = read(sock,buf,MAX_MSG_LENGTH);  //read stdout from program 
        printf("%.*s\n", ret, buf);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-12
      • 2021-03-17
      • 2014-02-21
      • 2011-12-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多