Boost asio tcp, почему у меня нет только одного сокета данных на стороне сервера, который можно открывать и закрывать

Вкратце, мой вопрос: если у вас есть tcp-сервер, который когда-либо будет иметь только одно активное соединение, вы можете просто создать один сокет данных на стороне сервера. Во всех руководствах я вижу, что создается новый сокет, и не понимаю, почему это должно быть так. Почему бы не создать один сокет на стороне сервера, а затем открыть, закрыть, сбросить его (что я изначально надеялся, что async_accept каким-то образом сработал)?

Более подробно:

Я прошел через руководство по boost asio для асинхронного дневного сервера и могу заставить его скомпилироваться и работать. Я даже могу изменить его для своего приложения и заставить его работать, как я хочу :). Однако мой первоначальный подход не сработал, и я не понимаю, почему именно здесь я надеялся на вашу помощь.

По сути, я хотел создать TCP-сервер, который будет принимать только одного TCP-клиента и игнорировать все остальные, если только этот первый клиент не отключится. Я сделал это с помощью acceptor.close () и acceptor.open (), так что, когда первое соединение было принято, я просто закрыл акцептор, а затем всякий раз, когда я обнаруживал ошибку eof, я снова открывал акцептор для прослушивания новых соединений. Я наивно думал, что, поскольку мне когда-либо требовалось только одно активное соединение, мне нужно было создать только одно:

boost::asio::ip::tcp::socket socket_

Поскольку у меня когда-либо был только один сокет данных, получающий данные от клиента, кажется излишним создавать целый класс tcp_connection в соответствии с учебником, который, насколько я мог судить, возвращал только новый сокет, созданный с помощью io_service. (В учебнике я думаю, что каждый раз, когда сервер принимает новое соединение, с помощью этого кода создается новый сокет):

class tcp_connection
  : public boost::enable_shared_from_this<tcp_connection>
{
 public:
  typedef boost::shared_ptr<tcp_connection> pointer;

  static pointer create(boost::asio::io_service& io_service)
  {
    return pointer(new tcp_connection(io_service));
  }

  tcp::socket& socket()
  {
    return socket_;
  }


 private:
  tcp_connection(boost::asio::io_service& io_service)
    : socket_(io_service)
  {
  }

  tcp::socket socket_;
  std::string message_;
};

Поэтому я попытался использовать только один boost :: asio :: ip :: tcp :: socket. Я инициализировал это в конструкторе своего серверного класса, используя io_service, аналогично тому, как это описано в руководстве выше. Мое тестирование показало, что мой первый клиент подключился, и только после того, как первый отключился, подключился второй. Однако, независимо от того, что я сделал, буфер данных при вызове async_accept (socket _, .....) никогда не будет заполнен. Сначала я просто продолжал получать ошибки eof, затем я попытался закрыть socked и повторно открыть, что удалило ошибку eof и дало ошибку транспортного конца, не подключенного. Очевидно, я делаю здесь что-то очень глупое, но я не вижу, что не так с философской точки зрения, говоря о том, что я пытаюсь сделать. Когда я создаю новый сокет, используя технику обучения, все работает, как ожидалось.

Итак, мой вопрос: могу ли я иметь только один сокет и делать что-то вроде отмены, закрытия, открытия? Я должен привязать или что-то еще, но это не задание async_accept?

Я использовал boost asio всего неделю, и это моя первая публикация на подобном форуме, так что не беспокойтесь;).


person user1759872    schedule 19.10.2012    source источник


Ответы (1)


Вы могли бы, но не можете.

Нет причин, по которым TCP не может быть реализован, как вы утверждаете, но ни одна известная мне операционная система этого не делает.

Причина довольно проста в том, что ОС должна поддерживать несколько одновременных подключений, и это требование дизайна, которое диктует реализацию. Чтобы достичь случая «может быть только один», просто закройте сокет слушателя после успешного принятия нового соединения и повторно откройте его позже. Обычно это не стоит усилий.

Описанные вами накладные расходы минимальны, и их не стоит пытаться оптимизировать.

person Brian White    schedule 19.10.2012
comment
Спасибо за Ваш ответ. Теперь из вашего ответа я понимаю, что ОС должна поддерживать несколько одновременных подключений, и согласен с тем, что усилия по оптимизации создания новых сокетов данных для каждого подключения, вероятно, не стоят никакого выигрыша. Меня все еще беспокоит, почему это просто не сработало, когда я попытался использовать единственный сокет данных (акцептор, но не сокет). Я просто напортачил при его реализации, или вы говорите, что есть фундаментальные причины, по которым этого не произойдет? - person user1759872; 22.10.2012
comment
Трудно сказать, потому что я не знаю, как библиотека Boost ведет свою бухгалтерию. Возможно, при копировании сокета подключения через прослушивающий сокет некорректно установлено какое-то внутреннее состояние. - person Brian White; 23.10.2012