Нарушение блокировки ReadFile () - именованный канал (Windows API)

Для упрощения, это ситуация, когда СЕРВЕР NamedPipe ожидает, пока КЛИЕНТ NamedPipe запишет в канал (с помощью WriteFile ())

Блокирующий Windows API - ReadFile ().

Сервер создал синхронный канал (без перекрывающегося ввода-вывода) с включенной блокировкой

Клиент подключился, и теперь сервер ожидает некоторых данных.

В обычном порядке клиент отправляет некоторые данные, а сервер обрабатывает их, а затем возвращается в ReadFile (), чтобы дождаться следующего фрагмента данных.

Тем временем происходит событие (например, ввод пользователя), и сервер NamedPipe SERVER должен выполнить другой код, чего он не может сделать, пока ReadFile () блокируется.

Здесь я должен упомянуть, что клиент NamedPipe не является моим приложением, поэтому я не могу его контролировать. Я не могу заставить его отправить несколько байтов, чтобы разблокировать сервер. Он просто будет сидеть и не отправлять данные. Поскольку у меня нет контроля над реализацией клиента, я не могу ничего изменить с этой стороны.

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

Из другого потока я пытался позвонить

 DisconnectNamedPipe()

и

 CloseHandle()

они оба не вернутся (пока клиент не запишет в канал).

Я не могу подключиться к тому же каналу и записать несколько байтов, потому что:

«Все экземпляры именованного канала имеют одно и то же имя канала, но каждый экземпляр имеет свои собственные буферы и дескрипторы и обеспечивает отдельный канал для взаимодействия клиент / сервер».

http://msdn.microsoft.com/en-us/library/aa365590.aspx

Мне нужен способ подделать это, поэтому вопрос на 64 тысячи долларов таков:

Как снять блокировку ReadFile ()?


person Mike Trader    schedule 27.02.2009    source источник


Ответы (7)


Попробуйте это перед ReadFile:

BOOL WINAPI PeekNamedPipe(
  __in       HANDLE hNamedPipe,
  __out_opt  LPVOID lpBuffer,
  __in       DWORD nBufferSize,
  __out_opt  LPDWORD lpBytesRead,
  __out_opt  LPDWORD lpTotalBytesAvail,
  __out_opt  LPDWORD lpBytesLeftThisMessage
);

if(TotalBytesAvail > 0)
  ReadFile(....);

-AV-

person Community    schedule 04.08.2009
comment
Это работает так, как заявлено, но предполагает, что в канале есть данные для чтения. Проблема в том, что нам нужен ReadFile () для блокировки ДО тех пор, пока не будут отправлены данные. Затем мы читаем данные и возвращаемся в состояние блокировки ReadFile (). Если мы не используем блокировку ReadFile (0, тогда нам нужно будет постоянно проверять канал (в первую очередь устраняя цель блокировки) - person Mike Trader; 06.08.2009

Взгляните на CancelSynchronousIo

Отмечает отложенные синхронные операции ввода-вывода, выполненные указанным потоком, как отмененные.

И CancelIo / CancelIoEx:

Чтобы отменить все ожидающие асинхронные операции ввода-вывода, используйте:

CancelIo - эта функция отменяет только операции, выполненные вызывающим потоком для указанного дескриптора файла.

CancelIoEx - эта функция отменяет все операции, выполняемые потоками для указанного дескриптора файла.

person alex2k8    schedule 27.02.2009
comment
Ооо. Я пропустил это ... Минимально поддерживаемый клиент Windows Vista Минимальный поддерживаемый сервер Windows Server 2008 К сожалению, это Windows Server 2003. Черт побери - person Mike Trader; 27.02.2009
comment
Google для статьи "Синхронный и асинхронный ввод-вывод msdn". Кажется, единственный оставшийся вариант - это TerminateThread, но это было бы плохой идеей (Google для 'msdn TerminateThread может привести к следующим проблемам') - person alex2k8; 27.02.2009
comment
Дополнительная информация здесь: msdn.microsoft.com/en-us/library/aa480216. aspx (поддержка отмены ввода-вывода Win32 в Windows Vista). - person dan-gph; 24.05.2009

Майк,

Вы не можете отменить синхронный ReadFile. Но вы можете переключиться на асинхронные (перекрывающиеся) операции. Поступая так, вы можете реализовать довольно масштабируемую архитектуру.

Возможный алгоритм (просто идея):

  • Для каждого нового клиента вызовите ReadFile
  • WaitForMultipleObjects, где ручки перекрываются. HEvent + ваши пользовательские события
  • Обходить сигнальные события и запланировать их выполнение потоками из пула потоков.

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

person alex2k8    schedule 27.02.2009
comment
да. Это следующий этап проектирования. к сожалению, я унаследовал большую часть этой проблемы. Мне не открыты ни IPC, ни спецификация FastCGI. У меня был длинный выстрел, но я подумал, что спрошу, если у кого-то есть техника для взлома блока. - person Mike Trader; 27.02.2009

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

Никогда в своей карьере я не обнаруживал, что «больше потоков» == «менее масштабируемо». Сколько у вас таких «серверных» экземпляров?

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

person Kevin    schedule 27.02.2009
comment
Сколько у вас таких экземпляров серверов? Они говорят о 10k ... Я знаю, что накладные расходы низкие, но идея состоит в том, чтобы минимизировать их. Я просто задаю вопрос ... возможно ли это? - person Mike Trader; 27.02.2009
comment
Да, для этого потребуется пул потоков, но дело в том, что есть накладные расходы на производительность, связанные с запуском нового потока, и каждому потоку также выделяется некоторая память для его стека и т. Д. Это складывается и нежелательно. - person Mike Trader; 27.02.2009
comment
Во-первых, вам не нужно убивать поток пула. Просто дайте ему поспать, пока он не понадобится в следующий раз. Прочтите эту статью msdn.microsoft.com/en- us / library / (это для .Net, но вы можете позаимствовать идеи) - person alex2k8; 27.02.2009

Асинхронные операции ввода-вывода не должны блокировать какой-либо поток, если они используют порты завершения ввода-вывода. См .: http://msdn.microsoft.com/en-us/library/aa365198(VS.85).aspx.

person Community    schedule 04.06.2009

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

person user3498796    schedule 23.03.2017
comment
Люди знали ответ на этот вопрос 8 лет, дружище, зачем отвечать сейчас? - person Droopy; 25.03.2017

Просто используйте SetNamedPipeHandleState функцию https://docs.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-setnamedpipehandlestate

При вызове этой функции используйте флаг PIPE_NOWAIT.

hNamedPipe должен быть дескриптором, возвращаемым функцией CreateFile.

После этого вызов ReadFile не будет блокировать поток при отсутствии данных.

person gil123    schedule 05.10.2020