Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: Mike TraderОтветов: 7

Для упрощения, это ситуация, когда СЕРВЕР 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 ()?

cc++winapinamed-pipes

Ответы

Ответ 1 · рейтинг 18 · Community

Попробуйте это перед 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-

Ответ 2 · рейтинг 6 · alex2k8

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

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

И CancelIo / CancelIoEx:

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

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

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

Ответ 3 · рейтинг 3 · alex2k8

Майк,

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

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

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

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

Ответ 4 · рейтинг 2 · Kevin

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

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

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

Ответ 5 · рейтинг 1 · Community

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

Ответ 6 · рейтинг 1 · user3498796

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

Ответ 7 · gil123

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

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

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

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы