Почему выходные данные клиента не выводятся на экран? - PullRequest
0 голосов
/ 17 апреля 2019

Я пытаюсь внедрить удаленный код через сокеты, но по какой-то причине при написании команды 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);

1 Ответ

1 голос
/ 17 апреля 2019

Как только вы получаете даже крошечную каплю данных, вы блокируете 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 в ожидании ввода, когда в приемном буфере сокета есть данные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...