сетевые задержки и применение-> ProcessMessages () - PullRequest
1 голос
/ 22 июля 2011

Я пишу сетевую DLL, которую я использую в своем проекте C ++ Builder. Эта DLL работает с удаленными FTP-серверами. Я заметил странное поведение, когда вызывается recv(). Иногда он возвращает 0. Но в другом потоке, когда в тот же сокет вызывается recv(), данные принимаются, как и ожидалось.

Что это значит? Я также заметил, что вызов Application->ProcessMessage() внутри потока DLL ускоряет получение данных.

Но что не так? ProcessMessages() не обрабатывает только оконные сообщения или я что-то упускаю?

Спасибо

Ответы [ 2 ]

3 голосов
/ 23 июля 2011

Если я вас правильно понял, и вы пытаетесь recv на том же SOCKET в параллельных потоках, тогда не делайте этого, от этого нечего получить. Данные, которые вы recv, уже буферизуются базовой системой, и вы получаете к этому доступ, и вы можете создать несколько буферов для recv, чтобы при возврате данных вы могли передавать один буфер в верхний уровни "для обработки и использовать другой для нового вызова recv. Вы также можете использовать только один большой буфер с уведомлениями, что для обработки и какая часть используется для получения. Система, вероятно, имеет блокировки, которые запрещают многократное чтение в одном сокете, поэтому результат в одном recv равен 0. Если бы этого не было, вы, вероятно, получили бы почти случайное разделение данных.

РЕДАКТИРОВАТЬ: Полное и полное объяснение

Я думаю, что использование нескольких потоков для чтения из одного сокета бесполезно Розетки - это программная вещь. Ваше сетевое устройство не создает никаких «подключений», оно просто обрабатывает полученные данные и упаковывает / разворачивает их в IP (или в любое другое поддерживаемые пакеты интернет-уровня) (предыдущий, в зависимости от сетевого устройства, некоторые из них почти полностью программно эмулируются операционной системой os и фактически выполняют только базовые услуги «write to tx-read rx», но для нас это то же самое). Сервис WinSock2 распознает пакеты с конкретными данными (как вы уже заметили), так что вы можете использовать одно сетевое устройство одновременно общение с несколькими сверстниками. WinSock2 активно следит за трафиком, прежде чем передать его вам. Другими словами: когда вы собираетесь получить успешные recv данные была уже там, и базовая система проверила сокет, который вы использовали в качестве параметра в recv, и передала вам только те данные, которые уже были помечены как данные для этого сокета. Чтение с нескольких потоков из одного сокета (без почти бесполезного MSG_PEEK) сделает систему, если она не имеет блокировок, скопирует неизвестное число байтов к расположению, указанному в recv в потоке 1, и постоянно увеличивайте внутренний указатель на данные на количество скопированных байтов, затем, перед тем, как все данные будут доступны в recv копируется в location1, другой поток запускает и копирует также неизвестное количество байтов, увеличивая таким образом внутренний указатель на данные на столько байтов. Результатом этого типа чтения в идеале должна быть половина данных, хранящихся из местоположения, переданного в потоке 1, а другая половина, начиная с местоположения, переданного в потоке 2. Поскольку идеальный результат является неопределенным (время, выделенное системой для этих двух потоков, не гарантированно будет равным) вы получите несортированные данные без каких-либо средств сортировки это, так как информация, которую базовая система использует для того, чтобы знать, какие данные принадлежат к какому сокету, вам не удастся.

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

  1. Создайте один поток чтения для каждого подключенного сокета и один циклический буфер, размер буфера зависит от размера чанков, которые вы ожидаете получить, и времени, которое вам потребуется для дальнейшей обработки содержимого, сохранения текущей позиции чтения, сохранения «обработать счет», когда данные получены, уведомить поток / потоки о том, что они должны обрабатывать данные в буфере, сохранить позицию данных, используемых для чтения, продолжить recv, если есть буферное пространство, не обрабатываемое иначе подождите, пока это не произойдет (необходимо реализовать это в случае, если ваш компьютер где-то захлебнется, в нормальных ситуациях это не должно). Вы должны синхронизировать принимающий поток с потоком / потоками обработки, когда они обращаются к переменным "to_process_count" и "current read pos", как они покажут Вы, какие байты вы можете использовать в циклическом буфере.

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

То, что вы тоже называете случайными потоками, читающими из одного сокета, может быть достигнуто через следующие сценарии:

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

или это может быть достигнуто с помощью чего-то подобного

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

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

Извините за длинный пост, орфографические и грамматические ошибки и надеюсь, что это вам немного поможет

1 голос
/ 22 июля 2011

Убедитесь, что сокет правильно связан с ручкой, которую вы используете в функции recv. Вы не можете ускорить прием данных, если нет канала для приема данных.

...