在客户端 - 服务器情况下将stdout重定向到套接字

时间:2015-04-16 13:27:04

标签: c linux sockets stdout dup2

我是这个论坛的新手,所以如果我的问题没有被正确询问,我很抱歉。我会尽量保持清醒。

我正在尝试在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),这将刷新所有缓冲区(包括套接字,如果客户端发送的命令非常短,这可能很有用)输出)。

非常感谢!

2 个答案:

答案 0 :(得分:0)

也许,你得到&#34;垃圾&#34;在客户端,当您的命令输出超过MAX_MSG_LENGTH时。 read(sock,buf,MAX_MSG_LENGTH);从socket读取MAX_MSG_LENGTH个字节,下一次当你从下一个命令中读取时,读取socket中的剩余字符。

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

  1. read返回读取的实际字节数。您可以将其与MAX_MSG_LENGTH进行比较,并决定再读一次。但是,如果您的实际数据恰好是MAX_MSG_LENGTH字节,那么您决定再次阅读并read阻止当前不可用的等待数据(以及stdin阻止,用户可以&#39; t发送新命令)。

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

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

  4. 使用select()机制同时读取套接字和用户输入&#34;&#34;。当任何数据可用时,它允许从多个文件描述符(套接字和stdio)读取。

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

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

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

答案 1 :(得分:0)

感谢您的回答!

我尝试将其添加到我的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;
    }
}

现在,在每个命令之后,客户端只打印发送的最后一个命令的输出。如果这个解决方案是正确的,我会更彻底地测试它并编辑我的原始帖子,所以非常感谢!