Должен ли я делать одновременные вызовы WSASend()?

Я знаю, что для одновременного вызова WSASend() мне нужно предоставить для каждого вызова уникальные экземпляры WSAOVERLAPPED и WSABUF. Но это означает, что я должен отслеживать эти экземпляры для каждого вызова, что все усложнит.

Я думаю, было бы лучше, если бы я создал поток, который будет выполнять только WSASend() вызовов не одновременно, а последовательно. Этот поток будет ждать в очереди, которая будет содержать WSASend() запросов (каждый запрос будет содержать дескриптор сокета и строку, которую я хочу отправить). Когда я в конце концов вызову WSASend(), я заблокирую поток до тех пор, пока не получу сигнал пробуждения от потока, ожидающего на порте завершения, сообщающего мне, что WSASend() завершен, а затем я перейду к получению следующего запроса.

Если это хорошая идея, то как мне реализовать очередь и как сделать для нее блокирующий вызов выборки (вместо использования опроса)?


person John    schedule 05.03.2015    source источник
comment
Первый вопрос заключается в том, может ли одноранговый узел понять смысл всей этой параллельной отправки. Может это действительно?   -  person user207421    schedule 05.03.2015
comment
@EJP Да, каждый вызов WSASend() будет отправлять сообщение определенной длины, не связанное друг с другом.   -  person John    schedule 05.03.2015
comment
Похоже, вы должны просто использовать для меня блокировку ввода-вывода с мьютексом для его последовательности. Гораздо проще, чем то, что вы предлагаете здесь.   -  person user207421    schedule 05.03.2015
comment
@EJP Но я хочу обслуживать тысячи клиентов, поэтому блокировка ввода-вывода не сработает.   -  person John    schedule 05.03.2015
comment
Если вы собираетесь использовать потоки отправителя, вы можете использовать механизм синхронизации для блокировки очереди при постановке в очередь/удалении очереди. Этого должно быть достаточно.   -  person jweyrich    schedule 05.03.2015
comment
Теперь, когда я думаю об этом, отслеживание экземпляров WSAOVERLAPPED и WSABUF не такая уж сложная задача по сравнению с созданием потока отправителя!   -  person John    schedule 05.03.2015
comment
@John Вы используете блокирующий ввод-вывод в соответствии с этим предложением, просто реализуя его самостоятельно поверх асинхронного ввода-вывода.   -  person user207421    schedule 06.03.2015
comment
@EJP У меня нет проблем с прямым использованием блокирующего ввода-вывода, если это позволяет мне обрабатывать тысячи клиентов. К сожалению, это разрешено только с перекрывающимся вводом-выводом.   -  person John    schedule 06.03.2015
comment
Правильное использование перекрывающихся операций ввода-вывода и IOCP позволяет масштабировать систему до многих тысяч одновременных подключений. Существует бесконечное количество способов, которыми вы можете предотвратить эту способность к масштабированию, делая что-то неправильно. Ваш пример — лишь один из них... Как говорит EJP, вы просто выполняете собственный блокирующий ввод-вывод, используя перекрывающийся ввод-вывод. Этот поток теперь заблокирован до тех пор, пока ввод-вывод не завершится, и ЭТО то, чего IOCP и перекрывающийся ввод-вывод (при правильном использовании) избегают...   -  person Len Holgate    schedule 06.03.2015


Ответы (1)


WSABUF может быть основан на стеке, поскольку WSASend() обязан дублировать его перед возвратом. OVERLAPPED и сам буфер данных должны существовать до тех пор, пока не будет извлечено и обработано завершение IOCP для операции.

Я всегда использовал «расширенную» структуру OVERLAPPED, которая включает в себя буфер данных, перекрывающуюся структуру И структуру WSABUF. Затем я использую систему подсчета ссылок, чтобы гарантировать, что «данные для каждой операции» существуют до тех пор, пока они никому больше не понадобятся (то есть я беру ссылку до того, как вызов API инициирует операцию, и я освобождаю ссылку, когда операция завершена после удаления завершение из IOCP - обратите внимание, что ссылки здесь не на 100% необходимы, но они упрощают передачу результирующего буфера данных в другие части кода).

НАИБОЛЕЕ оптимально для TCP-соединения иметь «размер окна» TCP для данных, находящихся в пути в любой момент времени, и иметь еще несколько ожидающих данных, чтобы окно всегда оставалось заполненным, и вы всегда отправляли максимум, что соединение могу взять. Чтобы достичь этого с перекрывающимся вводом-выводом, обычно лучше иметь много WSASend() ожидающих вызовов. Однако вам не нужно иметь слишком много ожидающих обработки (см. ="nofollow">здесь), и самый простой способ добиться этого - отслеживать количество байтов, которые у вас есть в ожидании, ставить байты в очередь для последующей передачи и отправлять из очереди передачи, когда существующие отправки завершены...

person Len Holgate    schedule 05.03.2015