Форум программистов, компьютерный форум, киберфорум
C++: Сети
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.52/29: Рейтинг темы: голосов - 29, средняя оценка - 4.52
183 / 181 / 66
Регистрация: 15.02.2015
Сообщений: 515

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

21.06.2016, 20:04. Показов 6286. Ответов 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
3406 / 2177 / 354
Регистрация: 13.01.2012
Сообщений: 8,444
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
3406 / 2177 / 354
Регистрация: 13.01.2012
Сообщений: 8,444
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
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru