powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Сокеты и библиотека boost::asio
14 сообщений из 14, страница 1 из 1
Сокеты и библиотека boost::asio
    #38530561
aybek_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Долго не мог решить в какой раздел форума обратиться с этим вопросом.
В исходном коде, как я понимаю, мы регистрируем функцию on_async_accept,
которая будет вызвана если на определенный порт поступит запрос на
соединение. Пробовал запустить эту программу и подключался с помощью
ncat. Функция вызывается.

$ Когда происходит новое подключение, то создается новый сокет привязанный к другому порту,
как я могу узнать какой этот порт, чтобы обмениваться данными с "клиентом"?

И вообще не бред ли строка начинающаяся со знака $

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
using boost::asio::ip::tcp;

int on_async_accept(const boost::system::error_code & ec) {
	std::cout << "We have connection!" << std::endl;

	return 0;
}

int main() {
	boost::asio::io_service	Service;
	tcp::socket			Sock(Service);
	tcp::acceptor			Acceptor(Service, tcp::endpoint(tcp::v4(), OPEN_PORT));

	Acceptor.async_accept(Sock, on_async_accept);
	Service.run();

	return 0;
}
...
Рейтинг: 0 / 0
Сокеты и библиотека boost::asio
    #38530566
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aybek_И вообще не бред ли строка начинающаяся со знака $
Бред конечно :)

aybek_$ Когда происходит новое подключение, то создается новый сокет привязанный к другому порту,
как я могу узнать какой этот порт, чтобы обмениваться данными с "клиентом"?
При accept новый сокет действительно создается, но порт у него тот же, что и слушающего сокета.

В любом случае назначенные сокету порты/адреса можно получить так:
Код: plaintext
1.
2.
boost::asio::ip::tcp::endpoint remote_ep = sock.remote_endpoint(); // IP:port другой стороны сокета
boost::asio::ip::tcp::endpoint local_ep = sock.local_endpoint(); // IP:port нашей стороны сокета
...
Рейтинг: 0 / 0
Сокеты и библиотека boost::asio
    #38530581
aybek_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Но как тогда возможно одновременно принятие других соединений и обмен данными через существующие?
...
Рейтинг: 0 / 0
Сокеты и библиотека boost::asio
    #38530586
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aybek_Но как тогда возможно одновременно принятие других соединений и обмен данными через существующие?
Каждое соединение идентифицируется кортежем из 4-х элементов: client_ip:client_port - server_ip:server_port.
У каждого нового соединения к одному и тому же серверу будет свой client_ip:client_port.
...
Рейтинг: 0 / 0
Сокеты и библиотека boost::asio
    #38530590
aybek_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
а как можно получить адрес созданного при подключении сокета?
...
Рейтинг: 0 / 0
Сокеты и библиотека boost::asio
    #38530591
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И так к слову, вам вообше не обязательно знать про порты чтобы принимать/отправлять данные.
Сокет как раз служит абстракцией более высокого уровня и снимает этот вопрос.

Еще одно.
Исходя из предыдущего моего сообщения, сервер может принимать произвольное (неограниченное портами сервера) кол-во соединений, так как его порты не расходуются.
Ограничение состоит только в наличии памяти на сервере и наличии свободных портов у клиентов.
...
Рейтинг: 0 / 0
Сокеты и библиотека boost::asio
    #38530592
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aybek_а как можно получить адрес созданного при подключении сокета?
А это я для кого писал?
Anatoly MoskovskyВ любом случае назначенные сокету порты/адреса можно получить так:
Код: plaintext
1.
2.
boost::asio::ip::tcp::endpoint remote_ep = sock.remote_endpoint(); // IP:port другой стороны сокета
boost::asio::ip::tcp::endpoint local_ep = sock.local_endpoint(); // IP:port нашей стороны сокета
...
Рейтинг: 0 / 0
Сокеты и библиотека boost::asio
    #38530598
aybek_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
С помощью сокет Sock мы слушаем, при подключении создается новый сокет,
говоря адрес сокета, я имел ввиду указатель на него или переменную, чтобы можно
было далее к этому сокету применять оперции read & write
...
Рейтинг: 0 / 0
Сокеты и библиотека boost::asio
    #38530695
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aybek_,

Самое простейшее - передавать ссылку на сокет в каждый обработчик одним из аргументов.
При этом разумеется ссылка/указатель должны оставаться валидными (указывать на все еще существующий объект) при вызове обработчика.
Для этого удобее всего использовать смартуказатели, например boost::shared_ptr.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;

typedef bost::shared_ptr<tcp::socket> socket_ptr;

boost::asio::io_service Service;
tcp::acceptor Acceptor(Service, tcp::endpoint(tcp::v4(), OPEN_PORT));

void start_accept()
{
	// создали новый сокет
	socket_ptr sock(new tcp::socket(Service));
	// принимаем следующее соединение
	Acceptor.async_accept(*sock, boost::bind(on_async_accept, boost::asio::placeholders::error, sock));
}

void on_async_accept(const boost::system::error_code & ec, socket_ptr sock) 
{
	if (ec == boost::asio::operation_aborted)
		return;
			
	std::cout << "We have connection! " << sock->remote_endpoint() << std::endl;
	
	// запустили чтение для сокета (ну или что там требуется согласно протокола)
	sock->async_read_some(...);
	
	// слушаем дальше
	start_accept();
}


int main() 
{
	start_accept();
	Service.run();

	return 0;
}



Но обычно, кроме сокета нужно еще много чего хранить, поэтому все организуют в виде класса Connection в котором сокет - одно из полей, а обработчики - методы этого класса, и таким образом неявно в каждый обработчик через this передается экземпляр класса, в котором есть все нужное состояние (включая сокет) для дальнейшей обработки соединения.
Чтобы эта схема работала с shared_ptr - почитайте про shared_from_this() - он служит для получения shared_ptr на текущий объект из метода этого объекта.

К сожалению поля этого форума слишком узки, чтобы я, после честно заслуженного пива, мог написать подробнее :)
Зато есть пример в доке Boost.Asio
http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/example/cpp03/echo/async_tcp_echo_server.cpp
...
Рейтинг: 0 / 0
Сокеты и библиотека boost::asio
    #38531260
aybek_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
получается, что вы создаете сокет, после того как на него подключается какой-то клиент,
вы просто передаете сокет обработчику, а сами уже создаете НОВЫЙ сокет и на нем заново
слушаете.
Как я правильно понял, принцип работы таков:
Вы создаете сокет и он сидит ждет подключения.
После того как к нему подключатся, он уже становится
не слушающим сокетом, а уже сокетом общения некого
клиента с сервером. После того как этот сокет стал
таким, вы берете и назначаете новый слушающий сокет,
которого ждет та же участь ).
Никакой сокет при acceptинге автоматически
не создается, не так ли?
...
Рейтинг: 0 / 0
Сокеты и библиотека boost::asio
    #38531265
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aybek_Как я правильно понял, принцип работы таков:
Вы создаете сокет и он сидит ждет подключения.
После того как к нему подключатся, он уже становится
не слушающим сокетом, а уже сокетом общения некого
клиента с сервером. После того как этот сокет стал
таким, вы берете и назначаете новый слушающий сокет,
которого ждет та же участь ).
Никакой сокет при acceptинге автоматически
не создается, не так ли?
Нет, вообще не так.
Слушает один и тот же сокет, тот что внутри объекта acceptor.
Объекты socket, которые создаются перед каждым приемом нового соединения, не несут в себе никакие сокеты пока не будет принято новое соединение. И только в момент прихода нового соединения объект acceptor создает в объекте socket реальный сокет для этого соединения.
...
Рейтинг: 0 / 0
Сокеты и библиотека boost::asio
    #38532736
aybek_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Аха, круто! Теперь все начало получаться.
Это часть кода где выполняется обработка принятых сообщений:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
		void on_async_receive(const boost::system::error_code & e) {
// здесь происходит вывод данных полученных от клиента на stdout
			for (char & c : in_buffer_) { 
				if (c == '\0') 
					break; 
 
				std::cout << c; 
				c = '\0';
			}

			std::cout << sock_->is_open() << std::endl;
// если сокет открыт мы снова регистрируем функцию для обработки
// поступивших данных
			if (sock_->is_open())
				sock_->async_receive(boost::asio::buffer(in_buffer_, BUF_SIZE),
							boost::bind<void>(&session::on_async_receive
							, this
							, boost::asio::placeholders::error));
		}


Функция is_open(), не возвращает false когда клиент отключается. А когда он выходит,
получается что функция рекурсивно себя ставит в очередь, и впустую тратятся ресуры

Вопрос: Нормальный клиент должен закрывать сокет перед тем как выйти?
Но все равно как узнать что клиент аварийно отключился и закрыть сокет?
...
Рейтинг: 0 / 0
Сокеты и библиотека boost::asio
    #38533129
Фотография Anatoly Moskovsky
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aybek_Функция is_open(), не возвращает false когда клиент отключается. А когда он выходит,
получается что функция рекурсивно себя ставит в очередь, и впустую тратятся ресуры

Вопрос: Нормальный клиент должен закрывать сокет перед тем как выйти?
Но все равно как узнать что клиент аварийно отключился и закрыть сокет?
Функция is_open() не для этого.

Чтобы узнать отключился ли клиент, надо проверять содержимое boost::system::error_code передаваемое параметром в обработчик.
Я даже больше скажу, перед тем как что-либо делать в обработчике надо обязательно проверить есть ли ошибка или нет, а не так как у вас.
Кроме того, в обработчике чтения/записи нужно объявлять также и параметр длины переданных данных, иначе вы не узнаете сколько получено, потому что не все асинх. функции читают ровно заданное кол-во данных.

Схема такая:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
void on_async_receive(const boost::system::error_code& e, size_t bytes_transferred)
{
   if (e) {
      // получена ошибка, обрабатываем
      
      if (e == boost::asio::operation_aborted)  {
        // сервис или сокет отменил операцию, ничего не делаем
        return;
      }
      if (e == boost::asio::error::eof)  { 
        // другая сторона закрыла сокет, завершаем обработку
        ....
        return;
      }
      // другая ошибка, обрабатываем и выходим
      ... 
      return;
   }
   
   // ошибок нет, читаем из буфера bytes_transferred байтов
   ...

   // стартуем следующее чтение
}
...
Рейтинг: 0 / 0
Сокеты и библиотека boost::asio
    #38533161
Andrej_f
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aybek_Вопрос: Нормальный клиент должен закрывать сокет перед тем как выйти?
Но все равно как узнать что клиент аварийно отключился и закрыть сокет?1. Должен; shutdown, closesocket.
2. В момент закрытия клиентом (или сервером) сокета функция чтения recv / recvfrom (или ожидания события - select) сокета вернет SOCKET_ERROR, а фунция WSAGetLastError покажет конкретную причину, например WSAESHUTDOWN = The socket has been shut down.
Тонкость - WSAGetLastError желательно (фактически - обязательно) вызывать сразу после функций работы с сокетом. Например, функция fwrite, вставленная между select и WSAGetLastError может исказить ошибку, возвращаемую WSAGetLastError.
...
Рейтинг: 0 / 0
14 сообщений из 14, страница 1 из 1
Форумы / C++ [игнор отключен] [закрыт для гостей] / Сокеты и библиотека boost::asio
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]