Сервер C ++ доменного сокета UNIX не может возвращать данные клиенту

Вот простой эхо-сервер, над которым я работаю, сервер примет запрос от клиента и вернет то, что клиент ему отправляет. Программа отлично работает с socat, но зависает при использовании моего собственного клиента.

Проблема моего старого кода в том, что я использую read вместо read_some. read будет блокировать канал до тех пор, пока он не прочитает определенное количество байтов или не получит исключение о неисправности канала, тогда как read_some будет читать фрагмент за раз. В обновленной версии read_some используется для чтения входного потока и проверки, является ли последний символ, прочитанный программой, \0, если это \0, это означает, что он достигает конца команды, поэтому он будет эхом отозваться. Это работает, потому что я передаю только строковые литералы, а в конвейере нет двоичных данных.

Код сервера

using namespace std;

const char* epStr = "/tmp/socketDemo";

int main() {
  namespace local = boost::asio::local;

  boost::asio::io_service io_service;

  ::unlink(epStr);

  local::stream_protocol::endpoint ep(epStr);
  local::stream_protocol::acceptor acceptor(io_service, ep);

  while(1) {
    local::stream_protocol::socket *socket = new local::stream_protocol::socket(io_service);
    acceptor.accept(*socket);

    char buf[2048] = {0};
    boost::system::error_code error;

    size_t len = 0;
      while(1) {
        len += socket->read_some(boost::asio::buffer(buf + len, 2048 - len));
        cout << "read " << len << endl;
        if (buf[len] == '\0') {
          break;
        }
      }

    cout << "read " << len << " bytes" << endl;
    cout << buf << endl;

    boost::asio::write(*socket, boost::asio::buffer(buf, len), boost::asio::transfer_all());
  }
}

При тестировании сервера командой socat, например

echo "12345" | socat - UNIX-CONNECT:/tmp/socketDemo

он вернет желаемый результат.

Мой клиентский код

const char* epStr = "/tmp/socketDemo";

int main(int argc, const char* argv[]) {
  boost::asio::io_service io_service;
  boost::asio::local::stream_protocol::endpoint ep(epStr);
  boost::asio::local::stream_protocol::socket socket(io_service);

  socket.connect(ep);

  boost::asio::write(socket, boost::asio::buffer(argv[1], strlen(argv[1])), boost::asio::transfer_all());

  char buf[1024] = {0};

  size_t len = 0;
    while(1) {
      len += socket.read_some(boost::asio::buffer(buf + len, 2048 - len));
      std::cout << "read " << len << std::endl;
      if (buf[len] == '\0') {
        break;
      }
    }

  std::cout << "read " << len << " bytes\n";

  std::cout << buf << std::endl;

  socket.close();

При выполнении клиента сначала у обоих нет вывода, после того, как я убил клиента, сервер выведет, что он прочитал n байтов и получит исключение сломанного канала.

Может ли это быть вызвано функцией read на сервере? Если да, то есть ли способ сообщить ему, сколько данных он должен прочитать, не отправляя размер блока данных в начале каждого сообщения? Мне также интересно, почему socat может без проблем работать с этим сервером? Спасибо!


person bxshi    schedule 04.01.2016    source источник
comment
используйте квалификатор static для epStr   -  person Ryan    schedule 05.01.2016
comment
@self, причем тут вопрос?   -  person SergeyA    schedule 05.01.2016
comment
Думаю, вы ищете read_some.   -  person David Schwartz    schedule 05.01.2016
comment
@DavidSchwartz спасибо, с ответом read_some и @llya я решил это.   -  person bxshi    schedule 05.01.2016
comment
Не используйте форматирование кавычек для текста, который не цитируется.   -  person user207421    schedule 05.01.2016


Ответы (1)


Мне также интересно, почему socat может работать с этим сервером без проблем?

Вероятно, потому что socat закрывает сокет, а ваш клиент - нет.

Если да, то есть ли способ сообщить ему, сколько данных он должен прочитать, не отправляя размер блока данных в начале каждого сообщения?

Например, чтение одного байта за раз, пока вы не прочитаете символ конца сообщения, предполагая, что вы определяете / используете протокол, который включает EOM.

person Ilya    schedule 04.01.2016
comment
Вы правы, я не закрыл сокет в своем клиенте. Спасибо что подметил это. Однако это не решит эту проблему ... Конец сообщения - хорошее решение, но я не знаю, может ли это решить эту проблему ... - person bxshi; 05.01.2016
comment
Двунаправленная связь не будет работать, если сервер ожидает фиксированного количества байтов (2048), в то время как клиент пишет меньше. Клиент должен отправить по крайней мере то количество байтов, которое ожидает сервер. - person Ilya; 05.01.2016
comment
@llya спасибо за подсказку. Я изменил свой код, используя read_some, и определяю, достиг ли конец ввода, проверяя, является ли последний символ \0 или нет. - person bxshi; 05.01.2016