首页 > 解决方案 > 为什么客户端的输出不会打印到屏幕上?

问题描述

我试图通过套接字注入远程代码,但由于某种原因,在编写命令cd或任何其他命令时,这反过来又通过客户端给我一个答案,答案不会输出到屏幕上。

我尝试了各种输出到屏幕的方法,但没有一种方法有效。

输出的服务器部分:

void *ReadAndWriteSocket(void *entrypoint) {

        char message[256];
        char buffer[256];

        while (1) {

        if((sockStructure.n = recv(sockStructure.newsockfd, buffer, strlen(buffer), 0)) > 0) { 


        for(int i = 0; i < strlen(buffer) - 1; i++) {

        printf("%s", buffer[i]);

        }

        }


        }
        scanf("%s", &message);
        send(sockStructure.newsockfd, message, strlen(message), 0);

}

客户端代码:

require 'socket'
require 'open3'

def createClient(hostname, port)

  s = TCPSocket.new hostname, port

    while line = s.gets
      if line == "exit"
        s.close
      elsif line[0..1] == "cd"
        output = Dir.chdir(Dir.pwd + "/" + line[2..line.size].delete(" \t\n\r\0"))
        s.puts(Dir.pwd)
      end
      stdin, stdout, stderr, wait_thr = Open3.popen3(line)
      s.puts("#{stdout.read}")
    end
end

createClient("127.0.0.1", 8082);

标签: csockets

解决方案


一旦您收到哪怕是最微小的数据,您就会阻止scanf而不是尝试接收更多数据。您要么需要同时支持在两个方向上移动数据(等待输入scanf和数据输入recv),要么在改变方向时需要更聪明。

考虑以下场景:

  1. 你打电话ReadAndWriteSocket
  2. 您的调用只recv得到一个“H”,即消息的第一个字节。
  3. 您将“H”传递给printf,但没有打印任何内容,因为您的标准输出是行缓冲的。
  4. 您打电话scanf并永远等待,但什么都没有发生,因为用户在看到收到的消息之前无意输入任何内容。
  5. 您的代码将永远不会recv再次调用,太糟糕了,因为接收到的消息的其余部分正在接收缓冲区中等待,但您被困在scanf.

当你的代码在两个方向移动数据时,你必须绝对确保当你应该等待的数据从另一个方向到来时,你永远不会阻塞等待接收数据。您的代码无法阻止这种情况。

更新:新代码的问题:

void *ReadAndWriteSocket(void *entrypoint) {

    char message[256];
    char buffer[256];

    while (1) {

    if((sockStructure.n = recv(sockStructure.newsockfd, buffer, strlen(buffer), 0)) > 0) {

这里发生了什么?您只能将字符串传递给strlen. 但buffer此处不包含字符串(它在第一次传递时未初始化,并且在后续传递中包含不相关的长度)。因此,您将长度的无意义值传递给recv.

    for(int i = 0; i < strlen(buffer) - 1; i++) {

    printf("%s", buffer[i]);

这里有两个问题:首先,buffer[i]不是字符串,%s格式说明符用于字符串。其次,标准输出是行缓冲的,所以除非缓冲区恰好包含一行,否则它不会显示。

    }

    }


    }
    scanf("%s", &message);

为什么要在这里等待用户输入?如果您只收到一小部分消息,甚至没有收到整行消息,因此还没有输出任何内容怎么办?你怎么知道接下来你需要做的是接收来自用户的输入而不是接收其余的消息?

    send(sockStructure.newsockfd, message, strlen(message), 0);
}

如果您有一些协议指定谁将在何时发送,谁将在何时接收消息,什么构成消息以及何时等待用户输入,则您必须编写实现该协议的代码。否则,当套接字的接收缓冲区中有数据时,您将陷入scanf等待输入的困境。


推荐阅读