【问题标题】:Linux C TCP Socket client/server with redirected output application具有重定向输出应用程序的 Linux C TCP 套接字客户端/服务器
【发布时间】:2013-03-23 02:03:33
【问题描述】:

首先让我说这是操作系统课程的家庭作业,我不是程序员,尤其不是 C帮助。我必须创建 TCP 客户端和服务器应用程序,其中将 linux 命令键入客户端,在服务器上执行并将输出重定向回客户端。我理解这个概念,我有 90% 以上的工作。 “ls”、“ls -lpq”、“cat somefile”、“man somecommand”等命令都可以正常工作。我遇到麻烦的地方是命令不返回任何信息,如“mkdir newdir”(如果目录已经存在,它可以正常工作,因为我得到了响应)。这对我来说是全新的,但在我看来,我的问题在于服务器的 recv 命令阻塞,因为没有信息可以接收。我不知道如何解决这个问题,我已经在这个问题上工作了一周。我的时间不多了,我还必须实现文件上传和下载,我不知道从哪里开始,但在我解决这个问题之前我什至无法开始工作。

谢谢

    // this is where I think the problem is
    while ((rcvd_bytes = recv(sock_fd, recv_str, sizeof(recv_str), 0)) > 0 ) {
        // Zero out the inputCopy buffer
        memset(&inputCopy, 0, sizeof(inputCopy)+1);

        // Copy the recv_str into a new string so that
        // we can work with it.
        strcpy(inputCopy, recv_str);

        argcount = parsecommand(inputCopy, args);

        //Send the message back to client
        dup2(sock_fd, 1);

        if((status = forkAndExecute(args)) != 0) {
            //printf("Command %s returned %d.\n", args[0], status);
        }

            // as a test is I uncomment the following line mkdir newdir
            // returns but the following commands are messed up - as I expect.
        //printf("\n");

        memset(&recv_str, 0, sizeof(recv_str)+1);
        fflush(stdout);
    }  

    if(rcvd_bytes == 0) {
    puts("Client disconnected");
    fflush(stdout);
    }
    else if(rcvd_bytes == -1) {
    perror("recv failed");
    exit(0);
    }

【问题讨论】:

    标签: c linux redirect tcp


    【解决方案1】:

    听起来你需要使用select

    if(select(fdmax+1, &my_fdset, 0, 0, NULL) > 0) // there is data available to be read
        recv(...)
    

    其中fdmax 是最大的文件描述符(select 想要 +1),my_fdset 是一个文件描述符集,您可以使用 FD_SET(sockfd, &my_fdset); 添加文件描述符。

    只有在有可用数据时才会收到。希望对您有所帮助。

    编辑:

    当我编写一个简单的客户端/服务器程序通过 TCP 套接字发送/接收字符串时,我问了一个类似的问题。我发布了我最终在该线程here 上使用的代码。我的不同之处在于我想要一个程序来发送和接收,但是如果您查看我的发送器或接收器功能,您可能能够调整一些东西以使您的程序执行您想要的操作。

    【讨论】:

    • 请点赞阅读我的想法。此外,poll 是一个具有类似功能的系统调用。您可以使用man 2 poll 在命令行上阅读它的文档。
    • @Wug - 谢谢!我昨晚刚刚完成了一个类似的程序:)
    • 我看这个很久了。客户端 recv 代码是我最初关注的,但我说服自己它是服务器。客户端代码是: // 接收来自服务器的回复 if ((n = recv(sockfd, reply, 10000, 0))
    • 抱歉代码格式问题,我试了三遍还是不行。
    • if(n=recv(...)) 将根据recv man page 将 n 设置为接收到的字节或 -1 错误。基本上,仅用于错误检查。即使那里什么都没有,它仍然会尝试recv(),从而阻塞。换句话说,它正在等待recv() 一条永远不会出现的消息,因此循环条件永远不会被评估为假(除非有一些错误条件并且recv() 返回-1)。所以use if(select(...)) 然后是你的if(n=recv(...))。将外部循环更改为 while(1) 之类的内容,然后检查某些条件以便 break 退出。
    【解决方案2】:

    根据您的问题描述,我怀疑是客户端代码而不是服务器代码 - 或者实际上是您在两者之间隐式创建的协议。

    看起来您只是通过使用dup2 将标准输出指向套接字将命令的输出直接发送回客户端。大概,客户端然后从套接字读取以获取命令的输出?当客户端向服务器发送命令然后没有得到回复时,客户端会做什么?像mkdir 这样的命令不会返回任何内容。是否永远等待服务器发送命令输出?

    一般来说,对于同步的客户端/服务器协议(客户端发送命令,服务器在客户端发送另一个命令之前发送响应),您必须在客户端和服务器之间就协议达成一致,以明确指示服务器何时完成发回数据,客户端应发送下一个命令。您可能需要添加一些方法让服务器告诉客户端命令已完成但未发送任何输出。

    【讨论】:

    • 我偷偷怀疑它的设计方式,它读取一行并发送它,然后它期望返回一些东西(它一次读取所有内容),将它转储到你的屏幕上,然后等待另一条线。我不认为双向访问有效。
    • 是的,这也是我的想法。所以当命令没有发回任何东西时,客户端会永远阻塞等待输出。
    • 我看这个很久了。客户端 recv 代码是我最初关注的,但我说服自己它是服务器。客户端代码是 // 接收来自服务器的回复 if ((n = recv(sockfd, reply, 10000, 0))
    • 是的,这将阻止等待服务器发送一些东西,所以如果服务器从不从命令发送回任何输出,我很确定它会永远等待。您的想法是正确的,即让服务器在命令输出后发送换行符。我认为你需要这样的东西,这样无论命令做什么,客户端都会得到一些输出。
    • 谢谢大家! rra 和 Wug - 当我被困在服务器上时,您将我重定向回客户端。 – JB0x2D1,我花了太多时间试图通过阅读来理解 select(),所以我决定深入研究并开始编码。我最终放弃了客户端代码并重新开始。在大多数情况下,我理解它,但我还有一些阅读要做。谢谢大家的帮助。
    猜你喜欢
    • 1970-01-01
    • 2016-02-09
    • 2016-08-30
    • 2018-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-17
    相关资源
    最近更新 更多