183 / 181 / 66
Регистрация: 15.02.2015
Сообщений: 515

Асинхронный tcp server

21.06.2016, 20:04. Показов 6298. Ответов 5
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Привет всем.
Пытаюсь реализовать класс - сервер, с которым в дальнейшем можно будет легко и непринужденно работать:
C++
1
2
3
4
5
TcpServer server(nPort);
server.BindRecvHandler([&server](Socket* s, staring&& b){ /*работаем с полученным сообщением */ });  //предположительно такая сигнатура
server.StartListen();   //асинхронно запускаем прослушку порта, аксептим сокеты и читаем сообщения, вызывая обработчик
/* выполняем операции параллельно с работой сервера */
server.StopListen();   //останавливаем работу сервера, join к потоку
Решение с синхронным сервером отпало, так как не хочу сильно ограничивать одновременное кол-во клиентов (много потоков не есть хорошо). Пока остановился на неблокирующих сокетах (только Беркли, без WSA функций), и "бесконечном" цикле в потоке:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
char buf[BUF_SIZE];
std::list sockets;
while (srv->IsWork()) {  //пусть будет atomic<bool>
    NativeSocket new_s = srv->socket.accept(...);  //NativeSocket - это typedef от системного сокета, srv->socket - прослушивающий сокет (врапер над NativeSocket)
    if (INVALID_SOCKET != new_s) {
        Socket s(new_s);  
        srv->OnAccept(&s);    //тут вызывается обработчик на подключение клиента
        sockets->push_back(std::move(s));
    }
    auto it = sockets.begin();
    while (it != sockets.end()) {
        int len = it->recv(buf, sizeof(buf));   //пытаемся прочитать сообшение с неблокирующего сокета
        if (SOCKET_ERROR != len)
            if (len == 0) {
                sockets.erase(it++);   //клиент штатно отключился
                continue;
            }
            else
                srv->OnRecv(&(*it), std::string(buf, len));  //обработчик полученного сообщения
        }
        ++it;
    }  //while (it != sockets.end())
    Sleep(1); 
} //while (srv->IsWork())
оно так-то работает, но эффективно ли такое решение? Остаётся загадкой, что делать с отвалившимися клиентами (в std::list они так и будет висеть). Думал сделать через select, но что поменяется? , только становится непонятно, как прерывать работу цикла, если поток повиснет в этом select (сервер неустанно ждёт клиентов и сообщений от них, и таймеры ни к чему).
Вообще, к подобному меня привела необходимость создания эмулятора modbus tcp server/slave, а сокетами занимаюсь всего несколько дней (не считая пары лаб в универе больше 6-и лет назад ).
Прикидывал как это можно сделать на boost::asio (тоже только начал разбираться), используя асинхронные методы, но не получится ли тогда, что каждый сокет, полученный аксептором, будет создавать для себя свой поток асинхронного чтения? В общем если есть адекватно решение этой задачи с использованием этой либы, я только рад.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
21.06.2016, 20:04
Ответы с готовыми решениями:

TCP server-klient
Проблема: Неработает &quot;связь&quot; между клиентом и сервером. Почем сервер не получет мои данные? client.cpp int main() { SOCKET...

TCP proxy server для СУБД с возможностью логирования всех запросов
Доброго времени суток! У меня есть задача:сделать TCP proxy server для СУБД с возможностью логирования всех запросов. Реализовать это...

Асинхронный или синхронный клиент TCP в приведенных примерах
Здравствуйте, подскажите пожалуйста это код синхронного или асинхронного клиента и сервера Клиент: using System; using...

5
Модератор
 Аватар для vxg
3407 / 2178 / 354
Регистрация: 13.01.2012
Сообщений: 8,448
22.06.2016, 08:01
Operok, можно сделать все в одном потоке на блокирующих сокетах если вы будете вызывать select для того чтобы узнать есть ли входящие подключения или данные и будет ли блокировка при accept или recv. select не вешает цикл. Но если такой сервер сильно нагрузить то он не сможет использовать процессор целиком - поток один и этому потоку доступно только одно ядро. Поэтому рационально создавать новый поток для обслуживания группы клиентов при необходимости. Отключившихся клиентов надо удалять из списка. Это немного усложняет схему управления потоками так как потоки могут разгружаться. Можно предусмотреть завершение полностью разгруженного потока или перераспределение клиентов между загруженными потоками при определенном уровне разгрузки потока плюс добавление нового клиента в группу к наименее загружённому потоку. Простор для творчества огромен однако у меня все отлично работает на блокирующих сокетах с select в одном потоке.
1
183 / 181 / 66
Регистрация: 15.02.2015
Сообщений: 515
22.06.2016, 17:03  [ТС]
vxg, разве select поток не блокирует, если последним параметром NULL передать? Отдельный select для серверного сокета тогда надо (отдельный fd_set) и в разные потоки, такое можно попробовать. Получится уже как минимум 3 потока (основной, select для accept и select для recv), если ещё кидать обработчик полученного сообщения в новый поток, то с одной стороны (если учесть конечное использование сервера) обработка модбас сообщений происходит довольно быстро имеет ли смысл создавать поток, а с другой стороны, если использовать сервер для задач с более длительной обработкой сообщений, то не накопится потоков многовато? Сделать thread pool? Это интересно
Как без лишних хлопот (без всяких счетчиков) узнать что клиент отвалился, не закрыв сокет? По крайней мере когда я вырубал консоль с работающим клиентом (в while(true) ), то серверу ничего не приходило от него. При штатном закрытии сокета прилетает сообщение нулевой длины.
0
Модератор
 Аватар для vxg
3407 / 2178 / 354
Регистрация: 13.01.2012
Сообщений: 8,448
22.06.2016, 18:53
Operok, а вы не передавайте в select null. Повторюсь - все может работать в одном потоке - и accept и recv. GUI я не рассматриваю как поток но если охото можно обработку и ему скормить через таймеры например или OnIdle. Смерть клиента можно по разному фиксировать. Да, при нештатном прерывании работы клиента вы можете сразу не увидеть что сокет закрылся, но рано или поздно система сама уведомит вас - тут уж ничего не изменишь разве что пинговать клиента
1
183 / 181 / 66
Регистрация: 15.02.2015
Сообщений: 515
25.06.2016, 14:21  [ТС]
Цитата Сообщение от vxg Посмотреть сообщение
Operok, а вы не передавайте в select null. Повторюсь - все может работать в одном потоке - и accept и recv.
Это я понял, нужно подать timeval с низким значением, так сказать вместо того же Sleep(...) будет давать "отдыхать" потоку в отсутствие нагрузки. Но у меня вопрос насчёт accept и recv в одном потоке: лучше два последовательных select или одним обойтись (прослушивающий сокет и те, что для клиентов, в один fd_set)? Спасибо.
0
183 / 181 / 66
Регистрация: 15.02.2015
Сообщений: 515
06.07.2016, 19:25  [ТС]
Может кто подсказать по boost::asio?
Как реализовать работу аналогичную с select (т.е. ждать что на один из множества сокетов придёт сообщение, после чего обработать его и снова ждать)? Выходит что есть два основных варианта: синхронные сокеты и асинхронные. Первый можно использовать, если для работы с каждым клиентом будем заводить поток , поэтому только второй:
вызов async_accept, в обработчике у полученного клиента, вызываем async_recive и следом следующий async_accept, в обработчике для async_recive обрабатываем сообщение и снова вызываем async_recive... и так до скончания веков. Как себя поведёт такой сервер при большом количестве клиентов?
Какие ещё могут быть варианты реализации такого сервера с применением asio?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
06.07.2016, 19:25
Помогаю со студенческими работами здесь

Асинхронный TCP сервер-клиент: не выходит считать поток
Ситуация у меня следующая: пишу приложение клиент-сервер, ну, в одном приложении и клиент и сервер, но работает либо-либо, просто для...

Соединение tcp client и tcp server
accept(); bind(); connect(); listen(); socket(); Нужно расположить их в порядке в каком их вызывает (А) сервер (Б) клиент, чтобы...

TCP-client and TCP-Server
Добрый день. Нужен сервер. В моем случае это пример-примитив. Проблема. Если я в IP клиента указываю 192.168.1.3(Мой ПК), то сервер с...

Tcp server
Нужен tcp сервер который будет получать одномерный массив с клиента на windows.

TCP server
Здарово народ, проблема вот такая, написал прогу... TCP server. public void StartListen(int port, ref RichTextBox userText) { ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Опции темы

Новые блоги и статьи
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR ВВЕДЕНИЕ Введу сокращения: аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi ветка по-частям. коммит Create переделка под биомассу. txt вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
Расчёт токов в цепи постоянного тока
igorrr37 05.01.2026
/ * Дана цепь постоянного тока с сопротивлениями и напряжениями. Надо найти токи в ветвях. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа и решает её. Последовательность действий:. . .
Новый CodeBlocs. Версия 25.03
palva 04.01.2026
Оказывается, недавно вышла новая версия CodeBlocks за номером 25. 03. Когда-то давно я возился с только что вышедшей тогда версией 20. 03. С тех пор я давно снёс всё с компьютера и забыл. Теперь. . .
Модель микоризы: классовый агентный подход
anaschu 02.01.2026
Раньше это было два гриба и бактерия. Теперь три гриба, растение. И на уровне агентов добавится между грибами или бактериями взаимодействий. До того я пробовал подход через многомерные массивы,. . .
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод. Thinkpad X220 Tablet —. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru