хочу дважды принять по одной розетке
То есть я слушаю порт (неподключенный сокет) и хочу получить два подключенных сокета в конце.
Сказано иначе, если я принимаю дважды на одном и том же сокете tcp, у меня возникают проблемы с распознаванием различий между двумя подключенными сокетами в asio. Это на Linux.
У меня относительно простой класс tcp-сервера. Предполагается, что все клиенты, которые могут подключиться к нему, являются однородными: если сообщение ожидает отправки клиенту, и ни одно из них не подключено, его можно отправить следующему клиенту, который подключится. Это прекрасно работает с одним подключенным сокетом, но теперь мне нужно прослушивать более одного сокета (то есть два клиента будут подключаться). Предположение об однородности все еще почти верно, но теперь у меня есть дополнительное ограничение, что если сообщение является ответом кому-то, оно должно быть передано этому человеку. (Ответы часто являются благодарностями.)
Я начинаю с того, что слушаю и принимаю:
short port = kSomethingKnown;
boost::asio::io_service& io_service_;
boost::asio::ip::tcp::socket socket_(io_service_);
boost::asio::ip::tcp::acceptor acceptor_(
io_service_,
boost::asio::ip::tcp::endpoint(tcp::v4(), port));
acceptor_.async_accept(socket_, [this](boost::system::error_code ec) {
if (ec) {
// Failed to accept. Schedule to try again (not shown).
return;
}
// Accepted.
SendMessage(); // Flush any old messages, appropriate with a single client.
ReceiveHeader();
});
Сравнение с интерфейсом разъема BSD
Остальное я объясню ниже, но это иллюстрирует главное. ПРИНЯТЬ (2) выглядит так:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
Возвращаемое значение, если оно не равно нулю, является файловым дескриптором подключенного сокета. То есть, если я на хосте H и слушаю порт P, то sockfd
представляет собой неподключенный сокет,
(H, P, tcp, 0, 0)
и возвращенный дескриптор файла представляет собой подключенный сокет,
(H, P, tcp, H1, P1)
где H1 - клиентский хост, а P1 - (вероятно, эфемерный) порт на клиенте, который является другой стороной этого сокета. Если я успешно приму второй раз, я получу другой подключенный сокет,
(H, P, tcp, H2, P2)
, где хотя бы один из H2 и P2 отличается от H1 и P1. Я не вижу в asio, как обращаться к этим двум соединенным сокетам. Я читал исходный код, который многому учит меня о том, как работает asio, но не о том, как работает async_accept
.
Вспомогательные данные
Fwiw, вот подробности отправки и приема звонков, но я думаю, что выше, это то, что мне действительно нужно. Как только я это понимаю, я использую эти подключенные розетки вместо socket_
.
SendMessage()
существует в форме, которая принимает сообщение (просто помещает его в очередь) и форму выше, которая обрабатывает очередь. Эта вторая форма выглядит так:
void SendMessage() {
if (WeAreDead()) {
// This checked that the connection seems valid,
// we aren't being asked to shut down, etc.
return;
}
if (send_queue_.empty()) {
// Nothing to send.
return;
}
boost::asio::async_write(
socket_, boost::asio::buffer(send_queue_.front()),
[this](boost::system::error_code ec, size_t length) {
if (ec) {
// Failed, schedule another attempt, not shown here.
return;
}
send_queue_.pop_front();
if (!send_queue_.empty()) {
SendMessage();
}
});
}
ReceiveHeader()
(и аналогичный ReceiveBody()
) выглядят аналогично, причем бит ключа является вызовом, который выглядит следующим образом:
boost::asio::async_read(
socket_, boost::asio::buffer(receive_buffer_, kTcpHeaderSize),
boost::asio::transfer_exactly(kTcpHeaderSize),
[this](boost::system::error_code ec, std::size_t received_length) {
Опять же, часть, которую я нахожу запутывающей, связана с async_accept()
.