Re[10]: winsock и порты завершения ввода-вывода
От: Pepel Беларусь  
Дата: 16.03.09 12:27
Оценка:
Gomes, немного касательно техники манипуляций со структурой OVERLAPPED :

Вы пишите :

> Всю остальную информацию в структуре, производной от OVERLAPPED для каждой операции.


производная структура — лепим сами структуру некую

struct MY_OVERLAPPED {

поля базовой структуры OVERLAPPED ;

мои добавочные поля ;

}

а дальше явное приведение типа используем там, где требуется , так ?
Re[11]: winsock и порты завершения ввода-вывода
От: Gomes Россия http://irazin.ru
Дата: 16.03.09 12:35
Оценка: 2 (1)
Здравствуйте, Pepel, Вы писали:

P>производная структура — лепим сами структуру некую


P>struct MY_OVERLAPPED {


P>поля базовой структуры OVERLAPPED ;


P>мои добавочные поля ;


P>}


P>а дальше явное приведение типа используем там, где требуется , так ?


В целом да, только удобней так:
typedef struct _PER_IO_DATA : public OVERLAPPED{
...

А в запросе приводим к LPOVERLAPPED.
Re[12]: winsock и порты завершения ввода-вывода
От: Pepel Беларусь  
Дата: 23.03.09 09:24
Оценка:
Вот толком не понял до конца — создал я сокет, далее мне требуется его дискриптор использовать в :

1. CreateIoCompletionPort для привязки к IOCP

2. последующих асинхронных вызовах

MSDN — CreateIoCompletionPort — "After an instance of an open file is associated with an I/O completion port, it cannot be used in the ReadFileEx or WriteFileEx function. It is best not to share such an associated file through either handle inheritance or a call to the DuplicateHandle function. Operations performed with such duplicate handles generate completion notifications."

я правильно понимаю — нужно обязательно плодить дубликат дискриптора сокета, для того чтобы разруливать 1.и 2. ? т.е. в асинхронных вызовах использовать именно копию дискриптора сокета , так ?
Re[13]: winsock и порты завершения ввода-вывода
От: Gomes Россия http://irazin.ru
Дата: 23.03.09 09:47
Оценка: 2 (1)
Здравствуйте, Pepel, Вы писали:

P>я правильно понимаю — нужно обязательно плодить дубликат дискриптора сокета, для того чтобы разруливать 1.и 2. ? т.е. в асинхронных вызовах использовать именно копию дискриптора сокета , так ?

Нет, не надо.
Re[7]: winsock и порты завершения ввода-вывода
От: maxlosyam Россия  
Дата: 24.03.09 13:12
Оценка: 3 (1)
Здравствуйте, Pepel, Вы писали:

P>по ходу интересно стало — поскольку accept() блокирует поток, то как народ этот поток завершает корректно ?


поделюсь опытом.

1. первый AcceptEx тоже ЖЕЛАТЕЛЬНО вызывать в рабочих потоках IOCP, потому что это красиво и гламурно.
зачем?
ну во первых если поток который вызвал первый AcceptEx завершится, то все его AcceptEx тут-же отменятся.
поэтому надо точно знать что поток который вызывает первый AcceptEx не завершится раньше времени.
это конечно может быть main thread, но можно просто сделать PostQueuedCompletionStatus со своим событием,
которое быстренько отработает в рабочих потоках, выполнит все что нужно включая первый AcceptEx.
остается только подождать завершения собственного события, или не ждать если вызов из незавершающегося потока.
2. в IOCP использовать только IOCP функции, AcceptEx, ConnectEx, WSARecv, WSASend, TransmitPackets, и.тд, никаких connect, accept
это священное правило IOCP
3. как закрыть сокет? смотри пункт 2!!! ТО ЕСТЬ — DisconnectEx, никаких closesocket на открытых сокетах, closesocket только после отработки
DisconnectEx, т.е только для того чтобы избавиться от хендла.
DisconnectEx это просто супер функция, тот кто ее написал просто красафчег, фукнция просто офигительно красиво завершает соединение по всем
правилам, и после того как соедиенние корректно закрыто, в IOCP получаем уведомление
а ещё хендл можно потом опять заюзать если указать TF_REUSE_SOCKET, ваще прелесть.
Re[8]: winsock и порты завершения ввода-вывода
От: Pepel Беларусь  
Дата: 26.03.09 14:51
Оценка:
Спасибо всем огромное, постигаю потиху ..изящная механика конечно, те, кто кидает какашки в Окна очевидно про winsock & iocp не слышали, у меня вопрос еще такой :

стартую WSARecv — на IOCP ловлю количество принятых, я могу столкнуться с ситуацией "буфер мал" и если да, то где — на IOCP или сразу на вызове WSARecv ?

по поводу WSASend — если я передал туда буфер с 500 байтами к примеру, а на IOCP ловлю запись, что передано всего 300 — такое может быть ? я так понимаю в любом случае буфер-передатчик после старта WSASend надо держать и не трогать до тех пор, пока на IOCP не словлю завершение отправки всех его данных — это так ?
Re[9]: winsock и порты завершения ввода-вывода
От: Gomes Россия http://irazin.ru
Дата: 27.03.09 06:10
Оценка: 3 (1)
Здравствуйте, Pepel, Вы писали:

P>те, кто кидает какашки в Окна очевидно про winsock & iocp не слышали

Да и вообще, не от большого ума.

P>стартую WSARecv — на IOCP ловлю количество принятых, я могу столкнуться с ситуацией "буфер мал" и если да, то где — на IOCP или сразу на вызове WSARecv ?

Для ТСР нет.

P>по поводу WSASend — если я передал туда буфер с 500 байтами к примеру, а на IOCP ловлю запись, что передано всего 300 — такое может быть ?

Может. Писать надо с учетом этого. На практике можешь никогда не столкнуться.

P>я так понимаю в любом случае буфер-передатчик после старта WSASend надо держать и не трогать до тех пор, пока на IOCP не словлю завершение отправки всех его данных — это так ?

Так. Буфер-приемник тоже
Re[10]: winsock и порты завершения ввода-вывода
От: Michael Chelnokov Украина  
Дата: 27.03.09 22:15
Оценка: 2 (1)
Здравствуйте, Gomes, Вы писали:

P>>я так понимаю в любом случае буфер-передатчик после старта WSASend надо держать и не трогать до тех пор, пока на IOCP не словлю завершение отправки всех его данных — это так ?

G>Так. Буфер-приемник тоже

И структуры OVERLAPPED тоже.
Re[9]: winsock и порты завершения ввода-вывода
От: maxlosyam Россия  
Дата: 27.03.09 22:27
Оценка: 2 (1)
Здравствуйте, Pepel, Вы писали:

P>стартую WSARecv — на IOCP ловлю количество принятых, я могу столкнуться с ситуацией "буфер мал" и если да, то где — на IOCP или сразу на вызове WSARecv ?


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

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

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

на практике самая эффективная модель это — пул буферов.
т.е, тебе надо определить максимальное кол-во байт которое ты принимаешь за запрос, например 8 кило.
создаешь класс-пул который при старте выделяет н-ть буферов (сколько буферов тебе надо для работы зависит от нагрузки)
лучше объясню кодом

class IOBuffer : public OVERLAPPED // OVERLAPPED с буффером в связке
{
PBYTE pData;
public:
IOBuffer(void)
{
pData = new BYTE[8192]
}
// и.тд
}

class IOBufferPool : public ну тупо vector
{
public:
IOBufferPool(int nMaximumBuffers = 10000)
{
for(int i = 0; i < nMaximumBuffers; ++i)
push_back(new IOBuffer);
}
// и.тд
}

void ReadData(int howMany)
{
IOBuffer* pBuffer = pIOPool->pop();
WSARecv(ну понятно);
}

void WriteData(ну типа так-же);

void OnDataReceived(IOBuffer* pBuffer, int howMany)
{
DoSomething(pBuffer->getData());
pIOPool->push_back(pBuffer);
}

void OnDataSent(IOBuffer* pBuffer, int howMany)
{
pIOPool->push_back(pBuffer);
}


ну конечно это примитивно описал, но вроде идея понятна.
плюс этого метода в очень высокой производительности, буферов валом и не надо делать new и delete которые любят кушать проц
минусы — фиксированный размер буфера, но это не страшно, 10 гигов можно по 8 килобайт потихоньку принять
и то что количество буферов надо выделять много, чтобы не кончились. т.е надо рассчитать сколько надо программе при полной загрузке.
выделять буферы дополнительно, когда кончаются — плохой тон, если буферы начнут где-то утекать (не возвращаться в пул) то прога упадет только тогда когда вся память уйдет лучше пусть упадет тогда когда они кончатся, будешь знать что мало или где-то утекают.
но пул-буферов это в основном серверная модель, но IOCP и применим в основном в серверах

P>по поводу WSASend — если я передал туда буфер с 500 байтами к примеру, а на IOCP ловлю запись, что передано всего 300 — такое может быть ? я так понимаю в любом случае буфер-передатчик после старта WSASend надо держать и не трогать до тех пор, пока на IOCP не словлю завершение отправки всех его данных — это так ?


вообще вроде бы теоретически IOCP может вернуть что отправил всего 300, но по моему это просто невероятно, так что лучше не напрягаться, и знать что если сказал отправить 500 то отправится 500. если IOCP вернет что отправил 300, то 100% с ошибкой типа порт закрылся или вообще интерфейс пропал

да, пока IOCP не вернет тебе буфер — буфер его, и OVERLAPPED структура тоже.
Re[10]: winsock и порты завершения ввода-вывода
От: Pepel Беларусь  
Дата: 03.04.09 06:57
Оценка:
Салют друзья-коллеги, тут походу вопросов у меня насобиралось :

1. Дескриптор сокета — я так понимаю безотносительно к конструкциям на которые он дает привязку это обычное число unsigned long и, получив его при создании сокета (WSASocket()), могу в рамках процесса смело гонять из функции в функцию до тех пор пока closesocket() на дескрипторе не отработаю, а ф-ция DuplicateHandle() — для межпроцессовой передачи доступа к объектам и нафиг в рамках одного процесса не нужна.

2. Вызов listen(..) — второй параметр задает размер очереди для клиентов на ожидание подключения, смотрел пару примеров народ туда 1 лепит, а почему не SOMAXCONN константу ? — ведь в этом случае согласно хэлпу размер данной очереди будет == вменяемому максимуму. Я так понимаю стартовал я AcceptEx() — словил на IOCP его завершение и тут ж надо как можно быстрее опять стартовать AcceptEx() — а все клиенты которые в этот промежуток будут цепляться станут в очередь — если размерность очереди это позволит, т.е. в listen над погуще лепить второй параметр, никак не 1.

3. Выяснение удачи-неудачи завершения асинхронной операции — я так понял анализа возврата GetQueuedCompletionStatus() предостаточно, вызов WSAGetOverlappedResult() продублирует данную информацию, ничего нового не даст и по сути не нужен.

4. Поведение в случае сбоя :

сбойнул AcceptEx() — не важно где просек — сразу на старте или на завершении в IOCP обработчике — я так понимаю сервис надо стопорить по любому, потому как дальше бодаться уже дорого и успех не гарантирован ;

сбойнули WSASend()/WSARecv() — не важно где просек — сразу на старте или на завершении в IOCP обработчике — можно грохнуть клиентский сокет и забыть про него — сервис пусть продолжает работать ;

или все ж аналитика сбоя какая-никакая нужна ?
Re[11]: winsock и порты завершения ввода-вывода
От: maxlosyam Россия  
Дата: 03.04.09 07:39
Оценка: 2 (1)
Здравствуйте, Pepel, Вы писали:

P>Салют друзья-коллеги, тут походу вопросов у меня насобиралось :


P>1. Дескриптор сокета — я так понимаю безотносительно к конструкциям на которые он дает привязку это обычное число unsigned long и, получив его при создании сокета (WSASocket()), могу в рамках процесса смело гонять из функции в функцию до тех пор пока closesocket() на дескрипторе не отработаю, а ф-ция DuplicateHandle() — для межпроцессовой передачи доступа к объектам и нафиг в рамках одного процесса не нужна.


ы, ну само собой, а что кто-то DuplicateHandle в одном процессе юзает?

P>2. Вызов listen(..) — второй параметр задает размер очереди для клиентов на ожидание подключения, смотрел пару примеров народ туда 1 лепит, а почему не SOMAXCONN константу ? — ведь в этом случае согласно хэлпу размер данной очереди будет == вменяемому максимуму. Я так понимаю стартовал я AcceptEx() — словил на IOCP его завершение и тут ж надо как можно быстрее опять стартовать AcceptEx() — а все клиенты которые в этот промежуток будут цепляться станут в очередь — если размерность очереди это позволит, т.е. в listen над погуще лепить второй параметр, никак не 1.


я леплю напрямую 200, где-то вычитал что в серверной винде начиная с w2k это потолок.

The standard method of determining the maximum number of backlogged connections is to use the
SOMAXCONN constant, which is supposed to represent the maximum number that an OS will support
(for example, 5 on Windows 2000 Pro, and 200 on Windows 2000 server)


P>3. Выяснение удачи-неудачи завершения асинхронной операции — я так понял анализа возврата GetQueuedCompletionStatus() предостаточно, вызов WSAGetOverlappedResult() продублирует данную информацию, ничего нового не даст и по сути не нужен.


WSAGetOverlappedResult просто для Overlapped сокетов, а не для IOCP. у IOCP — GetQueuedCompletionStatus.

P>4. Поведение в случае сбоя :


P>сбойнул AcceptEx() — не важно где просек — сразу на старте или на завершении в IOCP обработчике — я так понимаю сервис надо стопорить по любому, потому как дальше бодаться уже дорого и успех не гарантирован ;


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

P>сбойнули WSASend()/WSARecv() — не важно где просек — сразу на старте или на завершении в IOCP обработчике — можно грохнуть клиентский сокет и забыть про него — сервис пусть продолжает работать ;


ну в IOCP сбоит редко что, а все ошибки обычно получаешь уже по GetQueuedCompletionStatus. ну и ес-но легче просто закрыть сокет на любом неудачном результате, а что с ним ещё делать?

P>или все ж аналитика сбоя какая-никакая нужна ?

аналитика нужна для логов, так что всегда нужна.
Re[11]: winsock и порты завершения ввода-вывода
От: Gomes Россия http://irazin.ru
Дата: 03.04.09 10:21
Оценка: 2 (1)
Здравствуйте, Pepel, Вы писали:

P>2. Вызов listen(..) — второй параметр задает размер очереди для клиентов на ожидание подключения, смотрел пару примеров народ туда 1 лепит, а почему не SOMAXCONN константу ?

Лепи SOMAXCONN, listen сам разберется.

P>Я так понимаю стартовал я AcceptEx() — словил на IOCP его завершение и тут ж надо как можно быстрее опять стартовать AcceptEx()

Так. Только предварительно лучше стартовать несколько AcceptEx. Сколько — зависит от предполагаемой нагрузки.
Re[12]: winsock и порты завершения ввода-вывода
От: maxlosyam Россия  
Дата: 03.04.09 13:44
Оценка:
Здравствуйте, Gomes, Вы писали:

G>Здравствуйте, Pepel, Вы писали:


P>>Я так понимаю стартовал я AcceptEx() — словил на IOCP его завершение и тут ж надо как можно быстрее опять стартовать AcceptEx()

G>Так. Только предварительно лучше стартовать несколько AcceptEx. Сколько — зависит от предполагаемой нагрузки.

А точнее лучше столько AcceptEx сколько рабочих потоков, т.е по AcceptEx'у на поток больше смысла нету, быстрее не будет.
ну а рабочих потоков лучше столько сколько процессоров (ядер), имхо так оптимально быстро получается.
Re[12]: winsock и порты завершения ввода-вывода
От: Pepel Беларусь  
Дата: 03.04.09 14:02
Оценка:
Спасибо всем, вот на практике уперся в то, что поскольку возможна ситуация, когда WSASend() может отправить только часть данных, то мало толку выходит от его вызова в асинхронном режиме — все равно вызывай его пока все не затолкаешь — а если между такими асинхронными заталкиваниями в очередь IOCP станет запись от других обработчиков на передачу данных в этот же сокет. Я понимаю , что ситуация частичной отправки редкая, но по хорошему ее следует учитывать и выстраивать конструктив обработки с учетом множественного вызова WSASend для передачи одного буфера. Тогда не проще ли синхронно в цикле толкать этим же WSASend пока все данные буфера не залетят в сокет ? Тоесть читаем асинхронно с ожиданием завершения на IOCP , а писать все таки в сокет синхронно. Поправьте если что-то не догоняю.
Re[13]: winsock и порты завершения ввода-вывода
От: Gomes Россия http://irazin.ru
Дата: 06.04.09 10:48
Оценка: 2 (1)
Здравствуйте, maxlosyam, Вы писали:

M>А точнее лучше столько AcceptEx сколько рабочих потоков, т.е по AcceptEx'у на поток больше смысла нету, быстрее не будет.

Таки лучше поболе, если требуется Само подключение устанавливается в ядре, и от наших потоков не зависит.
Вот что сами Microsoft-ы пишут:

A responsive server must always have enough AcceptEx calls outstanding so that any client connection can be immediately handled. The number of posted AcceptEx operations will depend on the type of traffic your server expects. A high incoming connection rate (because of short-lived connections or spurts in traffic) requires more outstanding AcceptEx calls than an application where the clients connect infrequently. It may be wise to let the number of posted AcceptEx operations vary between application-specific low and high watermarks, and avoid deciding on one fixed number as the magic figure.

http://msdn.microsoft.com/en-us/magazine/cc302334.aspx

M>ну а рабочих потоков лучше столько сколько процессоров (ядер), имхо так оптимально быстро получается.

Общая рекомендация — в 2 раза больше чем ядер. А так зависит от.
Re[13]: winsock и порты завершения ввода-вывода
От: Gomes Россия http://irazin.ru
Дата: 06.04.09 10:56
Оценка: 2 (1)
Здравствуйте, Pepel, Вы писали:

P>Спасибо всем, вот на практике уперся в то, что поскольку возможна ситуация, когда WSASend() может отправить только часть данных, то мало толку выходит от его вызова в асинхронном режиме — все равно вызывай его пока все не затолкаешь — а если между такими асинхронными заталкиваниями в очередь IOCP станет запись от других обработчиков на передачу данных в этот же сокет. Я понимаю , что ситуация частичной отправки редкая, но по хорошему ее следует учитывать и выстраивать конструктив обработки с учетом множественного вызова WSASend для передачи одного буфера. Тогда не проще ли синхронно в цикле толкать этим же WSASend пока все данные буфера не залетят в сокет ? Тоесть читаем асинхронно с ожиданием завершения на IOCP , а писать все таки в сокет синхронно. Поправьте если что-то не догоняю.

Оппаньки. Только недавно писал, что постиг всю красоту, и тут такое
Откуда у тебя "множественные вызовы WSASend"? Один вызов — одно завершение. Не надо лишнего придумывать.
Re[14]: winsock и порты завершения ввода-вывода
От: Pepel Беларусь  
Дата: 06.04.09 11:28
Оценка:
Gomes :

Здравствуйте, вот с чем столкнулся :

на порт прослушки моего сервис цепляются клиенты, я должен предобработать их запросы и передать другому удаленному сервису S — от него получить подтверждение о приеме и назад разогнать клиентам. мой подход с Вашей помощью : я стартую на клиентах асинхронно вычитку (WSARecv() для каждого) и словив ее завершение на IOCP (4 потока в пуле на 2процессорной системе) для некого клиента CLi — предобрабатываю пакет — и теперь должен передать его в сокет завязанный на удаленный целевой сервис S. поскольку в пуле потоков потоков более одного — я закрыл доступ к сокету целевого сервиса S критической секцией — ура, НО ! наставив асинхронных WSASend (топчу предобработанные данные от клиентов в сокет целевого сервиса S) в очередь IOCP я с чем сталкиваюсь на IOCP обработчике :

WSASend1 — целиком отправил буфер — от клиента A
WSASend2 — ЧАСТИЧНО !! (300 байт из 500) — от клиента B
WSASend3 — целиком отправил буфер — от клиента C
WSASend4 — целиком отправил буфер — от клиента D

на стороне целевого сервиса S это не проканает — там протокол прикладной и он ждет все пакеты в потоке целиком, там заголовки — в них длины пакетов и проче. Т.о. поскольку WSASend может отправить лишь часть пачки (это реалии — тут все понятно), то асинхронность в моей ситуации не союзник выходит . Я про это. Или я чет не догоняю.

>Только недавно писал, что постиг всю красоту, и тут такое


постиг че слово !! тока взаимность дается трудами .. IOCP ему ж цветы не подаришь и в рестор не сводишь.
Re[15]: winsock и порты завершения ввода-вывода
От: Gomes Россия http://irazin.ru
Дата: 06.04.09 11:43
Оценка:
Здравствуйте, Pepel, Вы писали:

P>на стороне целевого сервиса S это не проканает — там протокол прикладной и он ждет все пакеты в потоке целиком, там заголовки — в них длины пакетов и проче. Т.о. поскольку WSASend может отправить лишь часть пачки (это реалии — тут все понятно), то асинхронность в моей ситуации не союзник выходит .

Не понимаю. Ну отправь оставшиеся 200 байт после завершения 300. В чем проблема?
Re[16]: winsock и порты завершения ввода-вывода
От: Pepel Беларусь  
Дата: 06.04.09 12:03
Оценка:
Здравствуйте, Gomes

G>Не понимаю. Ну отправь оставшиеся 200 байт после завершения 300. В чем проблема?


словил я завершение частичной вычитки WSASend — ЧАСТИЧНО (300 байт из 500) на одном из обработчиков IOCP — а обработчиков у меня боле одного — пока я кумекаю и леплю запрос на вычитку остатка — в это время любом другом параллельном обработчике (4 потока в пуле) тихо и мирно по факту завершения предобработки данных другого клиента вызывается WSASend () и этот вызов вклинивается между моими двумя WSASend (первые 300 байт) и WSASend (оставшиеся 200 байт), т.е. засада в том, что вычитанные данные от многих клиентов мне надо писать в один целевой сокет и частичная запись тут порет весь натюрморт
Re[17]: winsock и порты завершения ввода-вывода
От: perf13  
Дата: 06.04.09 12:05
Оценка: 3 (1)
Здравствуйте, Pepel, Вы писали:

Насколько я понял, у вас получается, есть несколько клиентов (на разных сокетах ясное дело), нужно принять он них данные, и потом отправить их серверу (в один сокет). Т.к. потоки байтов нескольких клиентов сливаются в один поток для отправки на сервер, нужно их правильно отправлять серверу, чтобы он на своем удаленном конце их там различил.
С асинхронностью тут противоречий нет. Просто вам нужно реализовать механизм, когда данные от клиентов будут уходить на сервер в правильной последовательности. Делайте асинхронный send, по завершении операции, если не все отправлено — снова асинхронный send, и так до тех пор пока нужный кусок данных от этого клиента не отправится серверу. Данные от остальных клиентов пока ждут своей отправки. Их можно принимать из сети и накапливать в ассоциированном с клиентом буфере. И так последовательно отправлять от каждого клиента. В результате прием не зависит от отравки.
Синхронный send вам тут кажется проще, но ведь он портит ваш асинхронный движок.
Вы учтите, что прием из сети может происходить быстрее чем отправка в сеть, либо ваша прикладная логика может генерить данные быстрее чем они уходят в сеть и тд. Поэтому нужно быть готовым что send не отправит все за один вызов, плюс еще и синхронно. Нужно быть готовым перестать принимать из сети от клиентов (в результате сработает tcp flow control), если они не будут успевать отправляться на сервер. Т.е. они могут к вам от клиентов прибывать быстрее, чем вы их будете успевать отправлять на сервер из-за разной скорости отправки по сети.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.