LINUX.ORG.RU

как реализовать проверку наличия ожидающих соединения клиентских сокетов

 ,


0

1

здравствуйте, в c# есть класс tcpListener, реализующий логику работы с серверным сокетом(bind, listen, accept)... там есть метод Pending, осуществляющий проверку наличия ожидающих на соединения клиентских сокетов https://msdn.microsoft.com/ru-ru/library/system.net.sockets.tcplistener.pending(v=vs.110).aspx... подскажите, как сделать проверку наличия ожидающих соединения клиентских сокетов на си? accept же метод только возвращает дескриптор нового сокета для общения с клиентом... а дальше не знаю что делать

If no pending connections are present on the queue, and the socket is not marked as nonblocking, accept() blocks the caller until a connection is present. If the socket is marked nonblocking and no pending connections are present on the queue, accept() fails with the error EAGAIN or EWOULDBLOCK.

Подробнее читай man 2 accept socket setsockopt.

pon4ik ★★★★★ ()
Ответ на: комментарий от pon4ik

я так понял нужно юзать select/poll... но это для неблокирующего сокета... а для блокирующего можно что-нибудь типа такого провернуть?

while(true)
{
   while(accept(...) == EAGAIN) {
      //задержка
   }
clienddescriptor =  accept(...);
}
?

xperious ()
Ответ на: комментарий от xperious

select/poll... но это для неблокирующего сокета... а для блокирующего

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

gag ★★★★★ ()
Ответ на: комментарий от xperious

Можно. Но принимать соединения придётся в отдельном потоке, на то они те сокеты и блокирующие. Что бы прервать такой поток читай про cancellation points.

Для блокирующих сокетов вполне можно использовать [e]poll/select, различия будут в основном при чтении и записи.

Лучше исползовать epoll или что-то типа libevent. Но минимум нужный для твоей задачи как ты её описал это неблокирующие сокеты :)

pon4ik ★★★★★ ()
Ответ на: комментарий от gag

вроде, насколько я знаю, асинхронный I/O в линуксе косячный(чем не шарю)... или это к сокетам не относится?

xperious ()
Ответ на: комментарий от xperious

Да. Иногда даже по две разумно сделать(на чтение и на запись) :)

Но в общем случае лучше aio. Тут уже зависит от задачи, с потоками хорошо когда мало подключений но требуется малое время отклика.

pon4ik ★★★★★ ()
Ответ на: комментарий от pon4ik

т.е. для блокирующих сокетов select/poll + на каждое соединение новая нить?

xperious ()
Ответ на: комментарий от xperious

Нет. Смотри, если тебе механизм полинга(по сути i/o очередь) вернул дескриптор, значит его можно прочитать/записать без блокировки.

Вот данные, обычно, уже обрабатывают в другом потоке. Хотя в той же nodejs всё делается в рамках одного потока. Или во всяких там asyncio в питоне.

Т.е. механизм такой: спим по таймауту на pselect или более новых api aio, если за таймаут ничего не случилось - процессим данные. И так в цикле. Называется такое event loop. Примерно так работают все gui библиотеки, только там своё api.

pon4ik ★★★★★ ()
Ответ на: комментарий от pon4ik

здравствуйте, в c# есть класс tcpListener

Никого не смущает?

Twissel ★★★★★ ()
Ответ на: комментарий от pon4ik

Я прочитал и этого не понял. Причем со ссылкой в ОП посте на MSDN

.NET Framework (current version)

:-)

Twissel ★★★★★ ()
Последнее исправление: Twissel (всего исправлений: 1)
Ответ на: комментарий от pon4ik

Точнее в независимости от того, случилось ли чего за таймаут, процессим порцию данных из очереди. А то, что считали с сети - кладём в хвост очереди.

pon4ik ★★★★★ ()
Ответ на: комментарий от pon4ik

я пока не дошел до select/poll/epoll, хотел реализовать по-тупому для начала: на каждое соединение одна нить, сокет блокирующий. вот никак не пойму, этот самый аналоги pending из c# tcplistener, как при таком подходе сделать? если это вообще возможно

xperious ()
Ответ на: комментарий от xperious

Возможно.

Один поток (например корневой) принимает соединения. В самом тупом случае можно на каждое соединение создавать поток. В этом потоке уже работать с дескриптором. Если надо параллельно читать и писать - нужно два потока на дескриптор. Потоки коммуницируют между собой обычно через очередь, в самом простом случае связанный список защищёный мьютексом и извещающий об изменении своего состояния кондиционной переменной.

pon4ik ★★★★★ ()
Ответ на: комментарий от xperious

В том то и дело, что pending из c# это идиома неблокирующего ввода вывода. Как и всякие readyToRead или как оно там называется в шарпах.

pon4ik ★★★★★ ()
Ответ на: комментарий от xperious

хотел реализовать по-тупому для начала: на каждое соединение одна нить, сокет блокирующий. вот никак не пойму, этот самый аналоги pending из c# tcplistener, как при таком подходе сделать? если это вообще возможно

А чего тут невозможного? Так традиционно и делалось в posix-системах. Поток, ожидающий соединения, спит, пока другой работает. Когда поступил запрос на соединение, поток создаёт клиентский сокет в ещё одном потоке (уже 3-ем) и снова засыпает, ожидая нового соединения. При небольшом числе одновременных соединений всё прекрасно работает. Вот если их будет слишком много, тогда из-за чрезмерного количества потоков могут исчерпаться ресурсы, и система начнёт тормозить.

Если одновременных соединений ожидается много, то можно использовать epoll/select. Тогда их все можно обработать в одном потоке поочереди (или даже в нескольких потоках, но в меньшем, чем число открытых соединений). Т. е. вызывать accept только для ожидающих соединений, тогда она не заблокируется. Хотя для надёжности можно ещё и перейти в неблокирующий режим с помощью ioctl. Но реализация усложнится. Плюс система периодически будет грузиться циклическим опросом дескрипторов.

Но при большом числе соединений, имхо, стоит рассмотреть возможность перехода с tcp на udp.

В общем, у каждого подхода свои достоинства и недостатки.

А про листенер из шарпа ничего не скажу, просто не знаю.

aureliano15 ()
Ответ на: комментарий от xperious

если тема решена, не забудь отметить её как решёную

pon4ik ★★★★★ ()
Ответ на: комментарий от Twissel

JB, причем здесь тег «си»?

видимо так же как и тег «нубы» - ни при чем

JB ★★★★★ ()
Ответ на: комментарий от pon4ik

я вот не понял: неблокирующий ввод/вывод это не тоже самое что асинхронный ввод/вывод?

xperious ()
Ответ на: комментарий от xperious

Вообще зависит от контекста. Но в контексте сокетов (и наверное posix в принципе) это разные вещи.

Неблокирующим ты можешь сделать дескриптор, тогда при операции ввода вывода блокировки не будет, но цикл будет крутится пока ты нюхаешь неблокирующие дескрипторы на предмет с кем можно сотворить ввод вывод.

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

Сумбурно и очень схематично получилось, но в голове моей оно живёт как то так :)

pon4ik ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.