с++ Как сейчас принято писать win приложение с асинхронными сокетами?
3. Вместо select быстрее использовать WSACreateEvent + WSAEventSelect + WSAWaitForMultipleEvents? Или select это просто обёртка, чтобы было привычнее тем, кто под bsd-socket'ы писать привык?с такими замашками лучше сразу ботать IOCP
а сколько клиентов-то планируется ?
спасибо!
при таком числе клиентов, где пора использовать IOCP, имхо уже надо с винды перелезать на что-то более сетевое.
IOCP - как раз про это читал только что. Так и не понял, что это. Это дозавершение операций на уровне операционки что ли?
сейчас используется шлюз на C# c SocketAsyncEventArgs. Там тоже какие- обратные вызовы. Вроде они даже иногда параллельно обрабатываются в разных тредах. Это и есть IOCP ?
да тут большого числа клиентов нет
Тогда лучше пиши синхронный код.
сейчас используется шлюз на C# c SocketAsyncEventArgs. Там тоже какие- обратные вызовы. Вроде они даже иногда параллельно обрабатываются в разных тредах. Это и есть IOCP ?Да, там используется IOCP.
Тогда лучше пиши синхронный код.
Синхронный точно не подходит. Если какой-то затык и send будет ждать пока клиет буфер разгребёт, все остальные клиенты будут ждать.
Синхронный точно не подходит. Если какой-то затык и send будет ждать пока клиет буфер разгребёт, все остальные клиенты будут ждать.а если синхронный, но по отдельному треду на каждого клиента?
можно конечно как-нибудь выкрутиться. А синхронная отсылка быстрее получается? или из каких соображений её советуете?
код меньше и проще
Так тоже хотел. Но даже send на предыдущие recv не должен тормозить обработку следующего recv.Так используй N потоков, а не один, тебе же написали.
да и жирно это как-то. Вот 20 клиентов - 20 тредов. память-то не резиновая.
Вот 20 клиентов - 20 тредов. память-то не резиновая.У меня вот сейчас >700 тредов работает и ничего. Обычная винда 7. Предел по идее больше 20000.
убедил. аргумент снимается.
пока send будешь делать, может следующее сообщение прийтикакая-то странная претензия, ни разу такого не видел.
No indication of failure to deliver is implicit in a send. Locally detected errors are indicated by a return value of -1.вроде send возвращается сразу, как только положил данные в ядерный буфер. блочится только если в буфере места не хватило. но можно же send делать из треда-обработчика по идее. ну или как там эта проблема решается в модели "по треду на запрос". короче, никогда не слышал, чтобы кто-то отказывался от "по треду на запрос" из-за того, что "пока send будешь делать, может следующее сообщение прийти". жаль, что не пользуюсь этой моделью, а то бы сказал точно, что там.
When the message does not fit into the send buffer of the socket, send normally blocks, unless the socket has been placed in nonblocking I/O mode. In nonblocking mode it would fail with the error EAGAIN or EWOULDBLOCK in this case. The select(2) call may be used to determine when it is possible to send more data.
в буфере места не хватило.
да, именно тогда.
Т.е. recv будет синхронным из треда-для-клиента.
а в некотором другом треде, одном на всех будет крутиться DLL.Recv(int timeout). Вот она получила ответ. и делает ..... что?
1. синхронный send ? - тогд встанет обработка вообще всей проги, если он сразу не отработает
2. асинхронный send - тогда принимаем синхронно, отправляем асинхронно. Так можно вообще?
3. отправляет данные в тред-клиент (как я подумал изначально).
Может что и пропустил.
у меня до 3к тредов бывает в приложении, предел зависит от размера стека не тред, настраивается ключем компиляции например. если сделать скажем 128к размер стека треда, то получим до 8192 тредов, потом исчерпается 2Гб адресного пространства, это под Win32. если произойдет стек оверфлоу в треде, винда накрутит автоматом кусочек стека, однако накручивает слишком щедро - сразу метр выдает.
а в некотором другом треде, одном на всех будет крутиться DLL.Recv(int timeout). Вот она получила ответ. и делает ..... что?я видел два варианта, которые работают:
1. синхронный send ? - тогд встанет обработка вообще всей проги, если он сразу не отработает
2. асинхронный send - тогда принимаем синхронно, отправляем асинхронно. Так можно вообще?
3. отправляет данные в тред-клиент (как я подумал изначально).
1) все треды одинаковые, кто-то произвольный из них акцептит внутри мутекса, как заакцептил - начинает обработку и отдает мутекс другому треду, который работает абсолютно так же (лочится и ждет, пока кого-нибудь заакцептит) - это вариант nginx (только в нем не треды, а процессы).
2) один тред крутится в event loop-е с неблокирующими сокетами, он же делает все send-ы и recv-ы в нужные моменты, а обработкой запросов занимаются другие треды - это вариант http://github.com/Begun/lizard
я вообще однопоточно пишу, делая все асинхронным, т.к. это самый быстро работающий способ, но так сложней всего писать, говорят.
собственно, странно, что я сразу не написал этого, ведь проблемы с тем,
что send заблокирует новые акцепты не существует в реальности!
типа:
void request_handler(void *arg)
{
char buf [4096];
int nb, sd = (int) arg;
nb = recv(sd, buf, 4096);
nb = send(sd, buf, nb);
close(sd);
return NULL;
}
...
for (;;)
{
struct sockaddr_in addr;
pthread_t tid;
int sd = accept(listen_fd, (struct sockaddr *) &addr, sizeof(addr;
if (0 > sd) continue;
if (0 != pthread_create(&tid, NULL, request_handler, sd
{
close(sd);
continue;
}
}
ну и там джойнить где-то надо треды
или детачить их, чтоб самоубивались при выходе
или в пуле сохранять...
можно треды не создавать а брать из пула
это как раз похоже на SocketAsyncEventArgs. Так сейчас.
что send заблокирует новые акцепты не существует в реальности!
для простоты считаем, что новых акцептов нет.
В общем, можно сделать так, если держать несколько дополнительных тредов.
создаём N + M тредов. Они извлекают из общей кучи N сокетов. Оставшиеся M ждут.
Как только что-то пришло один из N (пусть первый) начинает обработку, один из M ( пусть N+1 -ый) занимает сокет и ждёт оттуда новых сообщений.
Меня интересует, насколько эта модель проигрывает( и вообще проигрывает ли?) "всё в одном цикле"
я вообще однопоточно пишу, делая все асинхронным, т.к. это самый быстро работающий способ, но так сложней всего писать, говорят.
точно самый быстроработающий?
Пусть ограничение 60 клиентов стоит. select или WSAWaitForMultipleEvents могут сразу всех слушать.
а зачем делать второй recv во время обработки данных, полученных из первого?
у тебя возможна ситуация, когда ответ на первый вопрос посылается позже, чем ответ на второй
и при этом есть вопросы, на которые нужно отвечать в пределах нескольких миллисекунд?
если такая ситуация невозможна, то нужно просто в любом из N тредов делать:
recv(request_buf);
обработка(request_buf, response_buf);
send(response_buf);
потому что send заблокируется только если в ответ на предыдущие recv-ы никак не удается отправить ничего,
что в реальности вообще очень странная какая-то ситуация, ни разу такой не видел.
точно самый быстроработающий?в плане сетевой части - да, всегда и точно, даже стивенс это измерял.
если у тебя какие-то долгоработающие, cpu-пожирающие обработчики запросов, то мультитредный вариант может выиграть на мультипроцессорной тачке, потому что однотредный выжрет один проц и охуеет, а у мультитредного будет еще 7 штук в запасе. но никто не мешает опять же запустить 8 однотредных эвент-лупов на разных портах или нафоркать их при старте (вариант, который используется в nginx). поэтому при правильной эксплуатации, однопоточный асинхронный эвент-луп быстрее и тут.
но разница не очень большая там. 6-7 к 8-9 попугаям где-то.
и от протокола, конечно, тоже зависит, да! стивенс для более http-like штуки измерял,
а у тебя вообще какой-то странный dns, но по tcp...
впрочем, это все лирика, лучше на предыдущий пост ответь. =)
а зачем делать второй recv во время обработки данных, полученных из первого?
чтобы сообщения быстрее обрабатывались. грубо говоря, сообщение может обрабатываться DLL 10 секунд, но можно одновременно несколько заслать
Приходят с интервалом 100милисекунд от одного клиента 3 запроса. Если последовательно обработать - он получит 3 ответа через 30 секунд, а должен через 10сенкуд+ ещё чуть-чуть получить
в ответ на предыдущие recv-ы никак не удается отправить ничего
иногда ответы получаются достаточно большие. и они приходят почти подряд.
первый send выполнится, но не всё сообщение уйдёт. А второй сломается.
я бы не юзал кипалайвы в твоем случае, и юзал бы новый коннекшен на каждый 10-тисекундный запрос. это позволило бы заюзать простую и всем известную модель из nginx-а, когда одним сокет-дескриптором занимается только один тред. то есть не нужно было бы в мутекс оборачивать вызовы send и recv (и еще неизвестно, что в твоем случае делать с мутексом, если send готов, а мутекс ждет recv-а, короче, не верю я в эту изобретенную тобой модель с N+M тредами, заебешься ты ее писать имхо).
но можешь попробовать написать так, как ты хочешь, если ты такой отважный.
реальные данные где-то такие.
время обработки 20-30милисекунд. сообщения могут приходить хоть совсем подряд. <1ms между ними
время на установку соединения является существеннымможно UDP еще попробовать тогда.
время обработки 20-30милисекунд
типа делать recvfrom одного и того же адреса из нескольких тредов. каждый тред делает:
recvfrom(...);
обработка(...);
sendto(...);
не знаю, как у UDP с огромными ответами (достаточно ли просто буфер сокета подкрутить на обоих концах или есть еще подводные камни доставка соот-но тоже не гарантируется, но это можно опять же написать руками.
ну а с TCP (то есть с твоей N+M моделью) морока другая - придется в мутексы send и recv оборачивать, причем неясно, что делать, если send готов, а recv держит мутекс и в него ничего не приходит. надо таймауты будет ставить, короче тоже заебешься писать. тем более, таймауты - это огромный удар по латенси (готовый send будет ждать, пока recv затаймаутится)! может и хуже выйдет, чем с простой человеческой nginx-моделью.
поздравляю!
вообще, задача кажется какой-то пиздецовой и надуманной.
можешь описать содержательную часть? что там на самом деле у тебя приходит и обрабатывается?
почему не хочу здесь udp внедрять:
во-первых, не хочется, чтобы порядок пакетов мог поменяться.
во-вторых, реально не доходит часть. и я сомневаюсь, что смогу вот так вот и взять реализовать механизм переполучения данных лучше/быстрее, чем он в tcp сделан.
где-то здесь писали о каком-то протоколе http://en.wikipedia.org/wiki/Stream_Control_Transmission_Pro...
вроде как раз то, что нужно. Но он под винду сделан через какой-то драйвер. Вот сейчас хочу его заюзать. Если честно, сомневаюсь, что он вообще полетит.
вроде как раз то, что нужно. Но он под винду сделан через какой-то драйвер. Вот сейчас хочу его заюзать. Если честно, сомневаюсь, что он вообще полетит.я тоже сомневаюсь. =)
обрабатываются ответы от банка. нужно отсылать им всякие приказы, а ответ приходит результат выполнения операции.
для оповещения сетевого треда о том, что ответ сгенерирован библиотекой, Spin юзал пайп. писал в него байтик 'w' и читал его в том же евент-лупе, что и сетевые сокеты. работало типа. может проще способ есть, хз.
Вот я и подумал, а не окажется ли этот один большой процесс медленнее, чем много-много тредов непонятно(для меня) как работающих.
собственно, ты вот привёл инфу, что быстрее второй вариант скорей всего. Так что напишу что-нибудь тестовое. Посмотрю, насколько быстрее.
собственно, ты вот привёл инфу, что быстрее второй вариант скорей всего. Так что напишу что-нибудь тестовое. Посмотрю, насколько быстрее.Его вариант не быстрее, он более масштабируемый. Вполне может оказаться, что до 100 одновременных подключений более производительным будет синхронное решение.
Оставить комментарий
Phoenix
Задача такая.1. Подключается некоторое кол-во(не очень большое) клиентов. Новые клиенты могут появляться, но это очень редкая операция.
2.все сообщения нужно конвертировать в некоторый внутренний формат и отправить через закрытую dll. Ответы разконвертировать и оправить клиентам
DLL предоставляет такие функции.
AsyncSend(Message msg)
Recv(int timeout)
В самом простом варианте, вижу так:
while(1)
{
select(0, &clientlist, NULL, NULL, 1);
// обрабатываем сообщения от клиентов
Recv(1)
// обрабатываем сообщения от внутренний dll-ки.
}
1. Каким образом имеет смысл писать подобное? (операционка win2003) Может есть какие-то opensource приложения, которые очень чувствительны к задержкам?
2. Будут ли тормозить треды? Имеет ли смысл их использовать? 16мс не переключения - это в общем-то прилично для этой задачи.
3. Вместо select быстрее использовать WSACreateEvent + WSAEventSelect + WSAWaitForMultipleEvents? Или select это просто обёртка, чтобы было привычнее тем, кто под bsd-socket'ы писать привык?