2009-07-24 5 views
6

Я пишу сервер на основе завершения ввода-вывода (source code here), используя API-интерфейс Windows DLL на Python, используя модуль ctypes. Но это довольно прямое использование API, и этот вопрос направлен на тех, кто знает IOCP, а не Python.Порт ввода ввода-вывода ввода-вывода

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

Однако, скажем, я передаю 100 в качестве ключа завершения в моем вызове CreateIoCompletionPort с перекрывающимся объектом. Когда тот же перекрывающийся объект имеет свой IO, и он возвращается через GetQueuedCompletionStatus, ключ завершения, который сопровождает его, намного больше и не имеет никакого сходства с исходным значением 100.

Я не понимаю, как работает ключ завершения, или Должен ли я делать это неправильно в исходном коде, который я связал выше?

ответ

1

GetQueuedCompletionStatus возвращает две вещи, структуру OVERLAPPED и ключ завершения. Ключ завершения представляет информацию о каждом устройстве, а структура OVERLAPPED представляет информацию о каждом вызове. Ключ завершения должен соответствовать тому, что было дано при вызове CreateIoCompletionPort. Как правило, вы должны использовать указатель на структуру, содержащую информацию о соединении, в качестве ключа завершения.

Похоже, вы ничего не делаете с completionKey по возвращении GetQueuedCompletionStatus.

Я предполагаю, что вы хотите:

if completionKey != acceptKey: 
    Cleanup() 
    ... 

редактировать:

ли Python каким-то образом знает, что OVERLAPPED структура, созданная в CreateAcceptSocket используется асинхронно API Win32 и предотвратить его от GC» д?

+0

«Скажем, я передаю 100 в качестве ключа завершения в моем вызове CreateIoCompletionPort с перекрывающимся объектом. Когда один и тот же перекрывающийся объект имеет свой IO, и он возвращается через GetQueuedCompletionStatus, ключ завершения, который сопровождает его, намного больше и заставляет не похоже на первоначальное значение 100. " Из моего вопроса и почему я не сравниваю его в исходном коде. Возможно, вы правильно относитесь к перекрываемому объекту, который собирает мусор, но это не имеет отношения к вопросу. – 2009-07-25 05:36:26

0

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

Ключ завершения, переданный для принятого соединения, наложенного пакета - это то же, что и для прослушивающего сокета, а не для принимаемого сокета.

4

То, что я нашел в повседневной практике, состоит в том, что лучше всего сосредоточиться на результатах OVERLAPPED, так как это не изменится. Один из способов, которые вы можете использовать его эффективно, чтобы иметь что-то вроде следующего:

struct CompletionHandler 
{ 
    OVERLAPPED dummy_ovl; 
    /* Stuff that actually means something to you here */ 
}; 

Когда вы размещаете что-то к IOCP (будь то с помощью вызова I/O или просто пост через Win32 API), сначала создайте CompletionHandler, который вы будете использовать для отслеживания вызова, и введите адрес этого объекта в OVERLAPPED*.

CompletionHander my_handler; 
// Fill in whatever you need to in my_handler 
// Don't forget to keep the original my_handler! 

// I/O call goes here, and for OVERLAPPED* give: (OVERLAPPED*)&my_handler 

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

OVERLAPPED* from_queued_completion_status; 
// Actually get a value into from_queued_completion_status 

CompletionHandler* handler_for_this_completion = (CompletionHandler*)from_queued_completion_status; 
// Have fun! 

Для получения более подробной информации в реальных условиях, проверить выполнение BOOST по ASIO для Windows (ver 1.42 header here). Есть некоторые детали, такие как валидация указателя OVERLAPPED, который вы получаете от GetQueuedCompletionStatus, но снова см. Ссылку для хорошего способа реализации.

0

Ключ завершения не является указателем - это номер типа ULONG_PTR, который просто означает «целое число размером указателя», так что это 32-бит на x86 и 64-бит на x64. Имя типа запутывает, но когда имена win32 ссылаются на указатель, они делают это, имея перед собой имя P, а не конец.

0

Если ваше приложение многопоточно, убедитесь, что передаваемый вами CompletionKey является либо постоянным, либо значением указателя для объекта в куче, а не в стеке. В вашем примере, где 100 передается как константа, вы должны ошибаться, чтобы сказать какие-либо изменения. Но что касается проблемы, возможно, вы передаете дескриптор сокета в CreateIoCompletionPort, но не ссылку на дескриптор в GetQueuedCompletionStatus, чтобы получить его. Вы можете сделать

HANDLE socket; 
CreateIoCompletionPort((HANDLE)socket, existed_io_completion_port, (ULONG_PTR)socket, 0); 
/*some I/Os*/ 
... 

и

HANDLE socket; 
GetQueuedCompletionStatus(existed_io_completion_port, &io_bytes_done, (PULONG_PTR)&socket, &overlapped); 

и обратить внимание на тип в кронштейне.

1

Вы должны подумать о том, что ключ завершения используется как данные «для каждого соединения» и (расширенная) перекрывающаяся структура как операция «за i/o».

Некоторые люди используют расширенную перекрывающуюся структуру для ОБОИХ и сохраняют всю информацию, которая им нужна в расширенной перекрываемой структуре. Я всегда сохранял объект подсчета ссылок, который обертывает мой сокет в ключ завершения и буфер подсчитанных данных, как расширенную перекрываемую структуру. Если вас это интересует, вы можете увидеть some example IOCP code in C++ here.

Ключ завершения - это просто непрозрачный дескриптор данных, который система завершения ввода/вывода вернет вам, когда завершение произойдет в сокете.