Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

5ый семестр / 1. Производственная практика / стащил с работы / Начинающему сетевому программисту _ Хабр

.pdf
Скачиваний:
3
Добавлен:
18.07.2023
Размер:
890.47 Кб
Скачать

Начинающему сетевому программисту / Хабр

https://habr.com/ru/post/582370/

if (clientBuff[0] == 'x' && clientBuff[1] == 'x' && clientB shutdown(ClientConn, SD_BOTH);

closesocket(ServSock);

closesocket(ClientConn);

WSACleanup();

return 0

}

packet_size = send(ClientConn, clientBuff.data(), clientBuf

if (packet_size == SOCKET_ERROR) {

cout << "Can't send message to Client. Error # " << WSA closesocket(ServSock);

closesocket(ClientConn);

WSACleanup();

return 1

}

}

Пришло время показать итоговый рабочий код для Сервера и Клиента. Чтобы не загромождать и так большой текст дополнительным кодом, даю ссылки на код на

GitHub:

Исходный код для Сервера

Исходный код для Клиента

Несколько важных финальных замечаний:

В итоговом коде я не использую проверку на точное получение отосланной информации, т.к. при единичной (не циклической) отсылке небольшого пакета информации накладные расходы на проверку его получения и отправку ответа будут выше, чем выгоды от такой проверки. Иными словами – такие пакеты теряются редко, а проверять их целостность и факт доставки очень долго.

При тестировании примера также видно, что чат рабочий, но очень уж несовершенный. Наиболее проблемное место – невозможность отправить сообщение пока другая сторона не ответила на твоё предыдущее сообщение. Суть проблемы в том, что после отсылки сообщения сторона-отправитель вызывает функцию recv(), которая, как я писал выше, блокирует исполнение последующего кода, в том числе блокирует вызов прерываний для осуществления ввода. Это приводит к тому, что набирать сообщение и что-то отправлять невозможно до тех пор, пока процесс не получит ответ от другой стороны, и вызов функции recv() не будет завершен. Благо введенная информация с клавиатуры не будет потеряна, а, накапливаясь в системном буфере ввода/вывода, будет выведена на экран как только блокировка со стороны recv() будет снята. Таким образом, мы реализовали так называемый прямой полудуплексный канал связи. Сделать его полностью дуплексным в голой сокетной архитектуре достаточно нетривиальная задача, частично решаемая за счет создания нескольких параллельно работающих потоков или нитей (threads) исполнения. Один поток будет принимать информацию, а второй – отправлять.

В последующих статьях я покажу реализацию полноценного чата между двумя сторонами (поможет разобраться в понятии «нити процесса»), а также покажу полноценную реализацию прикладного протокола по копированию файлов с Сервера на Клиент.

Mr_Dezz

Теги: сокеты, windows, winapi, c++, сервер, клиент

Стр. 11 из 27

28.02.2022, 11:29

Начинающему сетевому программисту / Хабр

https://habr.com/ru/post/582370/

Хабы: C++, Visual Studio, API

+14

21K

113

9 0

Карма Рейтинг

@Mr_Dezz

Пользователь

Комментарии 49

k-morozov 08.10.2021 в 13:16

Сокет в С++ – это структура данных (не класс) типа SOCKET.

Тут все таки следует уточнить, что не в С++ сокет, а в конкретной библиотеке. С++ ничего не знает про сокеты. В том же boost::asio это класс.

+2 Ответить

Mr_Dezz 08.10.2021 в 21:58

Да, правильное замечание! Спасибо!

0 Ответить

DistortNeo 08.10.2021 в 13:20

Выбор C++/C для изучения сокетов, как мне кажется, не самый оптимальный. Слишком много отвлекающих технических сложностей. Плюс реализация сокетов в Винде сделана немного через жопу.

Лучше начать изучение с высокоуровневых кроссплатформенных обёрток в C#, Java, Python. А уже потом, при необходимости, опускаться на уровень API операционной системы.

Просто посмотрите, насколько кратко и выразительно выглядит код в Python: https://habr.com/ru/post/149077/

+3 Ответить

kozlyuk 08.10.2021 в 13:23

Вроде бы аккуратное изложение, и вдруг такое:

В итоговом коде я не использую проверку на точное получение отосланной информации, т.к. при единичной (не циклической) отсылке небольшого пакета информации накладные расходы на проверку его получения и отправку ответа будут выше, чем выгоды от такой проверки. Иными словами – такие пакеты теряются редко, а проверять их целостность и факт доставки очень долго.

Во-первых, потери пакетов здесь ни при чем. Их целостность и гарантию доставки обеспечивает ОС, мы уже выбрали это, когда создали потоковый сокет. Во-вторых, не обеспечивать фрейминг поверх потокового протокола --- это грубая ошибка, не надо такому учить. Не совсем про сокеты случай, но неделю назад у меня студент при передаче десятка байт(!) через локальный(!) named pipe словил проблемы из-за этого. Наконец, накладные расходы на проверку результата --- это ни о чем по сравнению с ценой системного вызова.

Чтобы избежать этих сложностей, проще начать с UDP и дейтаграммных сокетов, чтобы освоить API, а потом уже думать о буферах и протоколах.

+6 Ответить

Стр. 12 из 27

28.02.2022, 11:29

Начинающему сетевому программисту / Хабр

https://habr.com/ru/post/582370/

Mr_Dezz 09.10.2021 в 13:36

Спасибо за вдумчивый комментарий. Отвечу Вам так:

"...целостность и гарантию доставки обеспечивает ОС..."

Я бы даже по-другому сказал - обеспечивает не только и не сколько ОС, сколько сам протокол TCP/IP, который как раз для этого и был придуман, улучшив и расширив функционал UDP. Давайте будем откровенны: полагаться на ОС и транспорт в таком щепетильном вопросе - дело опасное. Тем более, что в критических случаях, когда потеря даже одного байта в процессе передачи, приводит к полной нефункциональности пересылаемого сообщения (например, передача по сети файлов *.exe), проверку целостности пакетов делать необходимо. И я честно написал, что не сделал этого, т.к. риски в конкретно этом приложении тут минимальны, но покажу как это сделать в сл. статьях, где буду развивать тему. Для первого знакомства с темой мне кажется представленной информации достаточно.

-1 Ответить

kozlyuk 09.10.2021 в 14:27

Извините, но вы смешиваете гарантии TCP и прикладной протокол.

TCP гарантирует, что все байты, которые одна сторона отдает в send(), другая сторона получит из recv(), причем в том же порядке. В случае порчи, потери, переупорядочивания пакетов при передаче данные будут оправлены повторно, причем программа об этом не узнает, это все сделает TCP-стек ОС. Если ничего не помогает, соединение отвалится. Именно так ОС гарантирует доставку и в этом смысле мы на нее полагаемся.

TCP --- потоковый протокол: приложение работает с потоком байт, а не с пакетами. Если клиент сделал send() на 10 байт, на сервере вызов recv() может выдать 10 байт, а может выдать 8 байт и на следующий вызов --- 2 байта. Если приложению требуется из этого потока выделять сообщения, нужно включить в прикладной протокол средства для этого (framing): длину перед сообщением, метку конца и т. п. Код обязан быть готов к тому, что recv() может вернуть меньше, чем запрошено, а send() может взять меньше, чем указано; при необходимости вызывать их несколько раз, разбирать фрейминг. Не делать этого я назвал грубой ошибкой. Это баг. Программа может сработать неправильно не потому, что в сети что-то случилось, а потому, что некорректно пользуется функциями. Учебный характер программы усугубляет это.

В протокол прикладного уровня может быть добавлена своя проверка целостности уже не пакетов, а сообщений. Спору нет, просто об этом еще и речи не шло.

P.S. TCP не "улучшает и расширяет" UDP, это протоколы для разных задач. TCP/IP --- это стек протоколов, UDP тоже работает поверх IP.

+5 Ответить

Mr_Dezz 09.10.2021 в 20:01

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

Ок, Вы считаете это серьезным багом - я покажу как такие баги исправляются в сл. статьях.

0 Ответить

kozlyuk 09.10.2021 в 21:08

Стр. 13 из 27

28.02.2022, 11:29

Начинающему сетевому программисту / Хабр

https://habr.com/ru/post/582370/

Фрейминг нужен для выделения сообщений из потока, только после этого можно говорить о проверке их целостности, например, добавляя к ним контрольную сумму. Если мы говорим о сообщениях (пишем-то чат), работать с TCP без фрейминга некорректно. Конкретно для вашей программы: клиент посылает "xxx", а на сервере recv() возвращает сначала "x", потом "xx" --- и все, не работает команда выхода. Или клиент посылает сначала "tax", потом "xxl" (двумя send), а на сервере recv() вернет "ta", потом "xxxl" --- и это будет воспринято как команда выхода, которую не посылали. В сети ничего не терялось и не искажалось, просто TCP-стек имеет право так отработать, а программа это не учитывает. Риск этого никак не зависит от алгоритма.

+5 Ответить

leahch 08.10.2021 в 13:33

Ух, какой сильный замес из posix и win32 API.

Как минимум в коде сервера следующие боольшие ошибки:

смешивание одного и второго, уж определитесь, либо микрософт, либо posix

зачем закрывать серверный сокет вместе с клиентским?

при акцепте нужно бы породить или тред или встать на select за fgets должна быть отдельная камера пыток

В общем, для новичков рекомендую классические примеры send-recv хотя бы отсюда https://docs.microsoft.com/en-us/windows/win32/winsock/windows-sockets-start-page-2

Ну или отсюда - https://rsdn.org/article/unix/sockets.xml

+6 Ответить

kozlyuk 08.10.2021 в 13:48

смешивание одного и второго, уж определитесь, либо микрософт, либо posix

Зачем, если можно учиться писать универсальный код, кроме пары мест?

при акцепте нужно бы породить или тред или встать на select

Автор же пишет, что оставил это на будущее.

за fgets должна быть отдельная камера пыток

Спутали с gets()? Хотя, конечно, при живом-то std::getline() просто не нужно.

+3 Ответить

Mr_Dezz 09.10.2021 в 13:53

Юзер @kozlyuk ответил за меня на все Ваши комментарии, за что ему спасибо :) От себя добавлю следующее:

1)"сильный замес из posix и win32 API" - никто и не говорил, что мы пишем программу исключительно с использованием WinAPI. Такой подход был бы крайне искусственной конструкцией, если не сказать более грубо. Задача была иной, а именно: показать каким образом написать и запустить простейшее клиент-сервер приложение под Windows и человеческим языком объяснить, что вообще за функции для этого используются с их детальным описанием.

2)"зачем закрывать серверный сокет вместе с клиентским?" - вопрос не в полной мере понимаю. Речь о месте кода в серверной части или в частях и клиента, и сервера?

3)"за fgets должна быть отдельная камера пыток" - опять же, не вполне понимаю, чем Вам не нравится данная функция? Как совершенно точно заметил @kozlyuk, реальная проблема возникает с другой функцией - gets(), которая дырявая и глубоко устаревшая. Функция же fgets() лишена минусов gets() (главная проблема этой функции - возможное переполнение буфера ввода и крах программы), при этом работает быстро и эффективно, решая нужную задачу для написанной в этой статье программы. Возможно Вы имели ввиду, что функция fgets() - это наследие

Стр. 14 из 27

28.02.2022, 11:29

Начинающему сетевому программисту / Хабр

https://habr.com/ru/post/582370/

С, однако, повторюсь, здесь она прекрасно работает и не усложняет при этом чтение программы. В целом наверное можно согласиться с тем, что "прогрессивнее" использовать более современную getline(), однако и мой вариант - это явно не ошибка.

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

0 Ответить

Tujh 09.10.2021 в 16:27

никто и не говорил, что мы пишем программу исключительно с использованием WinAPI

вы сами написали это в первом же предложении

Это приложение будет использовать Win32API

0 Ответить

Mr_Dezz 10.10.2021 в 14:46

Из этого никак не следует, что "мы будем использовать только Win32API". Подразумевалось, что мы будем использовать Win32API где это нужно, чтобы приложение работало под Windows для решения нашей конкретной задачи.

0 Ответить

Tujh 11.10.2021 в 11:00

Хорошо, тогда вопрос, что же было использовано из WinAPI кроме минимально требуемых WSAStartup/WSACleanup, о которых написано в любой статье по сокетам?

Тот же полный код простых клиента и сервера расположен в официальной документации Microsoft.

ZeroMemory спокойно меняется на вызов memset.

0 Ответить

Tujh 08.10.2021 в 14:04

подавляющее большинство написано под *nix-системы...Это приложение будет использовать Win32API

В итоге весь сетевой код таки на posix и ни каких WSASocket() вместо socket(), WSASend() вместо send() и так далее я не увидел.

Кстати жаль, потому что при таком подходе кроме select() ни чего продемонстрировать невозможно, а ведь WinAPI предоставляет много возможностей, начиная от простейших WSACreateEvent() и заканчивая IOCP.

фрагмент кода в примере от Microsoft по ссылке выше: service.sin_addr.s_addr = inet_addr("127.0.0.1");

вообще не заработает

Заработает, для этого в WinSock2.h определён специальный макрос

#define s_addr S_un.S_addr

0 Ответить

Mr_Dezz 09.10.2021 в 14:41

Стр. 15 из 27

28.02.2022, 11:29

Начинающему сетевому программисту / Хабр

https://habr.com/ru/post/582370/

@Tujh, спасибо за комментарий!

1) "В итоге весь сетевой код таки на posix "

Универсальность никогда не бывает лишней. Если серьезно, то я расширю именно WinAPI применение в следующих статьях, которые анонсировал в этой. Другое дело - уверенно утверждать, что такое использование существенно расширит функционал программы я бы не стал. А вот в универсальности точно будут потери. Более развернуто отвечал на подобный комментарий выше.

2) "Заработает, для этого в WinSock2.h определён специальный макрос #define s_addr S_un.S_addr"

Да, Вы правы - данный код всё-таки заработает (не считая того, что вызов функции inet_addr() недопустим в современных компиляторах, но этот момент можно пролечить спец. директивой). Странным образом при тесте этой строчки перед написанием статьи она вызывала ошибку компиляции. Возможно проблема была в моей системе. В целом же мне кажется недопустимым, что на сайте с документацией для строго типизированного языка программирования используется присваивание разных по типу сущностей в явном виде через подобные "скрытые" в библиотеке макросы. Приведенная конструкция с сайта Microsoft, это очень плохой стиль программирования, который скорее ухудшает читаемость кода, нежели помогает в нём разобраться.

0 Ответить

Tujh 09.10.2021 в 16:25

Другое дело - уверенно утверждать, что такое использование существенно расширит функционал программы я бы не стал

Я уже привёл пример, если ограничиваться в примерах только вызовом select(), то да, но чуть более серьёзное применении уже потребует или универсальности или функционала. Но и даже в таком варианте универсальности не получится.

По умолчанию в WinAPI вызов select() ограничен 64 сокетами

The default value of FD_SETSIZE is 64, which can be modified by defining FD_SETSIZE to another value before including Winsock2.h

https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-select

В Linux этот лимит установлен в 1024 и не может быть изменён в принципе

WARNING: select() can monitor only file descriptors numbers that are less than FD_SETSIZE (1024)—an unreasonably low limit for many modern applications— and this limitation will not change. All modern applications should instead use poll or epoll, which do not suffer this limitation.

https://man7.org/linux/man-pages/man2/select.2.htm

вызов функции inet_addr() недопустим в современных компиляторах

К компилятору это не имеет ни какое отношение.

Приведенная конструкция с сайта Microsoft, это очень плохой стиль программирования, который скорее ухудшает читаемость кода, нежели помогает в нём разобраться

Авот сейчас сами себе противоречите.

1.Это присваивание абсолютно легально с точки зрения posix реализации, которую вы называете - универсальной. То есть пример должен быть компилируемым в любом случае.

2.Так как реализация Microsoft не полностью совместима с posix им приходится делать код компилируемым с применением дополнительных средств, в данном случае - макроса, что может быть вводит в заблуждение порой, но совершенно нормально для переносимого кода.

3.Если следовать вашей логике, что "недопустимо так писать в официальной документации", то и INVALID_SOCKET является недопустимым. В posix только любое отрицательное значение сокета (тип данных - int) является недопустимым, а в WinAPI это специальный тип данных - SOCKET и значение INVALID_SOCKET == 0 противоречит идее универсальности, так как ноль - валидное значение для posix (не отрицательное).

Стр. 16 из 27

28.02.2022, 11:29

Начинающему сетевому программисту / Хабр

https://habr.com/ru/post/582370/

Небольшой совет, вы стараетесь обсуждать в статье вещи, в которых не разобрались, в этом и корень проблемы. Или "копайте глубже" или не будьте таким категоричным :)

+1 Ответить

brn 08.10.2021 в 14:18

Если сокет равен INVALID_SOCKET, то я бы настоятельно не рекомендовал его закрывать. Это некое служебное число за пределами массива сокетов. Как отработает его закрытие в разных реализациях я предпочитаю не думать.

https://www.opennet.ru/man.shtml?topic=socket&category=2&russian=0

0 Ответить

Mr_Dezz 09.10.2021 в 14:42

@brn, спасибо за комментарий. Принимается!

0 Ответить

redneko 08.10.2021 в 16:51

Еще одно пожелание как к программистам, так и к создателям ОС при работе с мультикастами: выдерживайте, пожалуйста, паузы при многочисленных подписках и отписках от групп, хотя бы по 10-20мс. Иначе коммутаторы сходят с ума. Если прибить процесс (или он сам упал по какой-то причине), который работает со многими группами - сама Windows штормом шлёт кучу IGMP Leave

0 Ответить

da-nie 09.10.2021 в 08:13

Другими словами все эти примеры просто не будут работать под Windows.

Почему вы так решили? Unix-системы используют posix-реализацию и она работает в Windows (с небольшими измененияминапример, в select в windows первый параметр 0, а в Unix максимальный номер сокета). Впрочем, я догадываюсь, что вас смущает событийная модель в windows (только вы её не используете :) )? Но вы можете просто создать отдельный поток и в нём реализовать все эти posix-сокеты. А если вас смущает их блокировка, то их всегда можно сделать неблокирующими. А так — честно, не увидел, что там у вас такого в коде специфичного для Windows? Инициализация? Она примитивна и описана очень много где (да хотя бы в «С++ глазами хаккера»). А событийную модель вы не используете. Строго говоря, вы накатали простейшую обработку сокетов, но ведь таких обучалок в инете навалом. Зачем же нужна ещё одна такого же уровня? Я не знаю. Честно, со стороны выглядит словно вы прочитав вступление к книжке по сокетам бросились рассказывать миру об этом откровении. Я так видел, как понявший суть *.h и *.c файлов помчался на радиокоте нести свет в массы, рассказывая, как их применять (а никто и не в курсе :) ). И это удивляет, словно мы докатились до ситуации, когда вещи, понятные лет 20 назад, теперь стали откровением. Удивительно…

А вот если вы с IEE1394 и связью с видеокамерами разберётесь… Вот это будет реально интересной вещью. Про такое статей и книг и не найти практически. Вот тут статья была бы нужна, несмотря на то, что шина устарела.

Обратите ещё внимание на «сырые сокеты» (RAW). Они позволяют отличненько лабать снифферы. :)

С одной стороны, меня радует, что кому-то ещё интересны сокеты на таком уровне, но с другой у меня вызывает удивление тот факт, что в 2021 году всё это оказалось благополучно забыто и требуются отдельные статьи (словно уже имеющихся недостаточно), чтобы это использовать.

0 Ответить

Стр. 17 из 27

28.02.2022, 11:29

Начинающему сетевому программисту / Хабр

https://habr.com/ru/post/582370/

Mr_Dezz 09.10.2021 в 15:05

@da-nie, спасибо за комментарий.

Он, правда, немного удивляет. Вот пишешь в начале статьи дисклеймер: "Она для начинающих", и тут прилетает такой вот комментарий )) Вы наверное забыли те времена, когда были студентом и имели ограниченный временной ресурс на поиск нужной неперегруженной информации. У этой статьи была очень чёткая цель - ввести в тему сокетов и показать работающую реализацию под Windows. Человеку, который ищет в интернете, как программировать сокеты, выпадает несколько тысяч ссылок с кодом в чистой posix-нотации. У него ничего не работает под Винду, он судорожно начинает искать информацию на сайте с документацией от Microsoft, но и там не всё гладко. Наконец, ему никто не расскажет, что отдельные описания есть в спец. литературе вроде "С++ глазами хакера" (она ещё есть в продаже-то?). Мне всегда казалось, что Хабр - это то место, где уютно сосуществуют люди, которые только начали свой путь в IT, и опытные специалисты. И это сосуществование должно быть мирным. Давайте так и будет.

В следующих статьях я разовью тему сокетов для Windows, и надеюсь Вас не разочарую :))

+1 Ответить

DistortNeo 09.10.2021 в 15:48

Собственно, поэтому у меня и был совет: вместо C++ использовать другой язык.

0 Ответить

da-nie 09.10.2021 в 16:40

Вот пишешь в начале статьи дисклеймер: «Она для начинающих»

Потому что таких статей валом. Это как статья «помигаем светодиодом на ардуино». При этом видно, что автор только недавно открыл для себя сокеты. :)

Вы наверное забыли те времена, когда были студентом и имели ограниченный временной ресурс на поиск нужной неперегруженной информации.

Я был студентом в 2000-2006 годах (и моя специальность с IT не связана). У меня инет был через модем с нефиговой почасовой оплатой на 56600 бод и поиск много времени не занимал (я книжки покупал — в них было много чего полезного). :) Времени же у меня вполне хватало на написание всяких 3D типа DooM, не говоря уж о всём остальном. :)

Человеку, который ищет в интернете, как программировать сокеты, выпадает несколько тысяч ссылок с кодом в чистой posix-нотации.

Вверху ссылки.

Вот, если конкретнее.

Просто надо указывать про Windows и статьи будут про неё.

Мне всегда казалось, что Хабр — это то место, где уютно сосуществуют люди, которые только начали свой путь в IT, и опытные специалисты.

А по-моему, это рекламная платформа разных контор. :) Вон их рейтинг, справа в верхнем углу. :) Спрашивают и рассказывают же на киберфоруме и подобных.

Стр. 18 из 27

28.02.2022, 11:29

Начинающему сетевому программисту / Хабр

https://habr.com/ru/post/582370/

Там и формат ответов удобнее.

0 Ответить

Mabu 10.10.2021 в 11:26

C:/Windows/System32

Что у вас с разделителями путей? Должно быть \ .

MAKEWORD(2,2)

Это не функция, это макрокоманда в заголовочных файлах, вы не найдёте её в виндовых DLL.

Но как же явно указать адрес и порт для привязки сокета?

Чтобы не возиться с приведениями к нужным типам, подсчётам 14 байт, каким то htons, используйте функцию GetAddrInfoW (или неюникодную оболочку над ней getaddrinfo), которая сама заполнит sockaddr, sin_addr и прочие sockaddr_in. К тому же

GetAddrInfoW можно использовать и для заполнения данных для функции connect.

После вызова данной функции (listen) исполнение программы приостанавливается до тех пор, пока не будет соединения с Клиентом, либо пока не будет возвращена ошибка прослушивания порта.

Нет. listen не блокирует поток, иначе вы не доберётесь до accept.

Привязка сокета к конкретному процессу (bind) не требуется, т.к. сокет будет привязан к серверному Адресу и Порту через вызов функции connect()

Всё же рекомендую привязывать клиентский сокет, чтобы вы могли выбрать через какой IP адрес и какую сетевую карту будут ходить ваши данные.

Вообще функции recv и send подходят только для учебных программ вроде телнета. Ни для GUI, ни для больших приложений это не походит, потому что они блокируют поток. Если у вас что то посложнее laba06.cpp, то также не мучайте select. Сразу используйте асинхронные сокеты и перекрывающиеся операции ввода вывода

(OVERLAPPED), WSAReceive и WSASend, для сервера — порт завершения ввода вывода.

0 Ответить

da-nie 10.10.2021 в 21:58

Вообще функции recv и send подходят только для учебных программ вроде телнета. Ни для GUI, ни для больших приложений это не походит, потому что они блокируют поток.

Так ведь

unsigned long nb=1; ioctlsocket(socket_server,FIONBIO,&nb);

И больше никаких блокировок.

0 Ответить

Mabu 11.10.2021 в 11:38

Неблокирующий режим — это ещё не асинхронный режим.

В неблокирующем режиме вам придётся проверять данные либо по таймеру, либо делая Sleep() между вызовами. Это хуже, чем создание отдельного потока. 1. Если данных нет, программа всё равно будет нагружать процессор проверками, разряжать батарею. И чем меньше период — тем выше нагрузка. 2. Данные обрабатываются не сразу при поступлении, программа не сможет отвечать на данные быстро. Например, это важно для торговых ботов.

Поэтому лучше сразу использовать асинхронные сокеты и перекрывающиеся операции.

Стр. 19 из 27

28.02.2022, 11:29

Начинающему сетевому программисту / Хабр

https://habr.com/ru/post/582370/

+4 Ответить

kozlyuk 11.10.2021 в 15:38

Зачем таймер? Поток же засыпает на вызове мультиплексора или функции ожидания.

0 Ответить

Mabu 11.10.2021 в 16:06

И опять пришли к блокировке потока и зависанию GUI?

Я пока вижу только два способа не блокировать GUI:

асинхронный сокет на оконных сообщениях через WSAAsyncSelect; OVERLAPPED операции ввода вывода + MsgWaitForMultipleObjectsEx.

Есть ли ещё какие нибудь способы без дополнительных потоков и таймеров не блокировать GUI?

+2 Ответить

da-nie 11.10.2021 в 17:57

Приличные люди всю обработку выносят в отдельные потоки. :)

0 Ответить

da-nie 11.10.2021 в 17:59

В неблокирующем режиме вам придётся проверять данные либо по таймеру, либо делая Sleep() между вызовами

Вас спасёт select/poll/epool.

Данные обрабатываются не сразу при поступлении, программа не сможет отвечать на данные быстро.

См. выше. Сможет и будет отлично работать. Я так рабочие столы и потоковое видео с камер передавал в одном проекте. К тому же в Unix нет никаких WSA-функций.

0 Ответить

Tujh 11.10.2021 в 18:02

К тому же в Unix нет никаких WSA-функций.

Вот только автор пишет

Это приложение будет использовать Win32API

0 Ответить

Стр. 20 из 27

28.02.2022, 11:29