2009-02-27 2 views
21

Для упрощения, это ситуация, когда именованный канал SERVER ждет для именованного канала КЛИЕНТА писать к трубе (с помощью WriteFile())Ломать ReadFile() блокирование - именованный канал (Windows API)

В Windows API что блокирование является ReadFile()

сервер создает синхронное трубу (не внахлест I/O) с блокировкой позволило

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

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

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

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

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

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

DisconnectNamedPipe() 

и

CloseHandle() 

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

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

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

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

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

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

ответ

1

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

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

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

+0

Сколько из этих «серверных» экземпляров у тебя есть? Они говорят о до 10k ... Я знаю, что накладные расходы низкие, но идея состоит в том, чтобы минимизировать это. Я просто задаю вопрос ... это возможно? –

+0

Я не думаю, что у вас могут быть потоки 10k :-) – alex2k8

+0

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

2

Mike,

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

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

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

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

+0

Да. Это следующий этап дизайна. к сожалению, я унаследовал большую часть этой проблемы. IPC не открыт для меня и не является спецификацией FastCGI. Я был длинным выстрелом, но я подумал, что спрошу, если у кого-то есть способ взломать блок. –

5

Посмотрите на CancelSynchronousIo

Marks в ожидании синхронного ввода/вывода операции, выпущенные указанного потока расторгнутым.

И CancelIo/CancelIoEx:

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

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

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

+0

Oooh. Я пропустил это ... Минимальная поддерживаемая клиент \t Windows Vista Минимальный поддерживаемый сервер \t Windows Server 2008 Unfortunatly это Windows Server 2003. Darn –

+1

Google для 'MSDN синхронного и асинхронного ввода/вывода' статьи. Кажется, единственный вариант - TerminateThread, но это было бы плохой идеей (google for 'msdn TerminateThread может привести к следующим проблемам:) – alex2k8

+0

Подробнее здесь: http://msdn.microsoft.com/en-us/library/ aa480216.aspx («Поддержка отмены Win32 I/O в Windows Vista»). –

11

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

+0

Это работает как рекламируется, но предполагает, что в считываемой трубе есть данные. Проблема в том, что нам нужно, чтобы ReadFile() блокировал UNTIL, там отправлены данные. Затем мы считываем данные и возвращаемся к статусу блокировки ReadFile(). Если мы не будем использовать блокировку ReadFile (0, тогда нам нужно будет постоянно проверять трубу (в первую очередь, преследуя цель блокировки) –

+0

Great Stuff, это также работает для анонимных труб –

0

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

+0

Люди знают ответ на этот вопрос вопрос для 8-летнего помощника, зачем отвечать сейчас? – Droopy

Смежные вопросы