|
| БЕСПЛАТНАЯ ежедневная online лотерея! Выигрывай каждый день БЕСПЛАТНО! |
|
|
Server Using Overlapped Input and Output
This example is a single-threaded server process that uses overlapped operations to service simultaneous connections to multiple client processes. The server process creates a fixed number of pipe instances, each of which can be connected to a separate client process. When a client process has finished using its pipe instance, the server disconnects from the client and reuses the pipe instance to connect to a new client.
Associated with each pipe instance is an OVERLAPPED structure containing an event object. This structure is specified as a parameter in each ReadFile, WriteFile, and ConnectNamedPipe operation on the pipe instance. Although the example shows simultaneous operations on different pipe instances, it avoids simultaneous operations on a single pipe instance. Because the same event object is used for read, write, and connect operations for each instance, there is no way to know which operation's completion caused the event to be set to the signaled state for simultaneous operations using the same pipe instance.
The event handles for each pipe instance are also stored in an array used by the WaitForMultipleObjects function. This function waits for one of the events to be signaled, and its return value is the array index of the event that satisfied the wait. The example uses this index to retrieve a structure containing information for the pipe instance. The server uses the fPendingIO member of the structure to keep track of whether the most recent I/O operation on the instance was pending, necessitating a call to the GetOverlappedResult function. It uses the dwState member of the structure to determine the next operation that must be performed for the instance.
Overlapped ReadFile, WriteFile, and ConnectNamedPipe operations may have finished when the function returns, or they may still be pending when the function returns. If the operation is pending, the event object in the specified OVERLAPPED structure is set to the nonsignaled state before the function returns. When the pending operation has finished, the system sets the state of the event object to signaled. The state of the event object is not changed if the operation finishes before the function returns.
Because the example uses manual reset event objects, the state of the event objects is not changed to nonsignaled by the WaitForMultipleObjects function. This is important, because the example relies on the event objects remaining in the signaled state except when there is a pending operation. If the operation is already finished when ReadFile, WriteFile, or ConnectNamedPipe returns, the function's return value indicates the result. For read and write operations, the number of bytes transferred is also returned. If the operation is still pending, the ReadFile, WriteFile, or ConnectNamedPipe function returns FALSE and the GetLastError function returns ERROR_IO_PENDING. In this case, the results are retrieved using the GetOverlappedResult function after the operation has finished. GetOverlappedResult returns only the results of operations that were pending, and does not report the results of operations that were completed before the overlapped ReadFile, WriteFile, or ConnectNamedPipe function returned.
Before disconnecting from a client, the multithreaded server example in the previous section used FlushFileBuffers to ensure that the client had read everything written to the pipe. This would defeat the purpose of overlapped I/O, because the flush operation would block the execution of the server thread while it waits for the client to empty the pipe. Consequently, it is necessary to wait for a signal from the client that it has finished before disconnecting. In this example, the signal is the error generated by trying to read from the pipe after the client process closes its handle.
#include #define CONNECTING_STATE 0 #define READING_STATE 1 #define WRITING_STATE 2 #define INSTANCES 4 typedef struct { OVERLAPPED oOverlap; HANDLE hPipeInst; CHAR chBuf[BUFSIZE]; DWORD cbToWrite; DWORD dwState; BOOL fPendingIO; } PIPEINST, *LPPIPEINST; VOID DisconnectAndReconnect(DWORD); BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED); VOID GetDataToWriteToClient(LPPIPEINST); PIPEINST Pipe[INSTANCES];
HANDLE hEvents[INSTANCES]; DWORD main(VOID) { DWORD i, dwWait, cbBytes, dwErr; BOOL fSuccess; LPTSTR lpszPipename = "\\\\.\\pipe\\mynamedpipe"; // The initial loop creates several instances of a named pipe // along with an event object for each instance. An // overlapped ConnectNamedPipe operation is started for // each instance. for (i = 0; i < INSTANCES; i++) { // Create an event object for this instance. hEvents[i] = CreateEvent(
NULL, // no security attribute TRUE, // manual-reset event TRUE, // initial state = signaled NULL); // unnamed event object if (hEvents[i] == NULL) MyErrExit("CreateEvent"); Pipe[i].oOverlap.hEvent = hEvents[i]; Pipe[i].hPipeInst = CreateNamedPipe( lpszPipename, // pipe name PIPE_ACCESS_DUPLEX | // read/write access FILE_FLAG_OVERLAPPED, // overlapped mode
PIPE_TYPE_MESSAGE | // message-type pipe PIPE_READMODE_MESSAGE | // message-read mode PIPE_WAIT, // blocking mode INSTANCES, // number of instances BUFSIZE, // output buffer size BUFSIZE, // input buffer size PIPE_TIMEOUT, // client time-out NULL); // no security attributes if (Pipe[i].hPipeInst == INVALID_HANDLE_VALUE)
MyErrExit("CreatePipe"); // Call the subroutine to connect to the new client Pipe[i].fPendingIO = ConnectToNewClient( Pipe[i].hPipeInst, &Pipe[i].oOverlap); Pipe[i].dwState = Pipe[i].fPendingIO ? CONNECTING_STATE : // still connecting READING_STATE; // ready to read } while (1) { // Wait for the event object to be signaled, indicating // completion of an overlapped read, write, or
// connect operation. dwWait = WaitForMultipleObjects( INSTANCES, // number of event objects hEvents, // array of event objects FALSE, // does not wait for all INFINITE); // waits indefinitely // dwWait shows which pipe completed the operation. i = dwWait - WAIT_OBJECT_0; // determines which pipe if (i < 0 || i > (INSTANCES - 1)) MyErrExit("index out of range");
// Get the result if the operation was pending. if (Pipe[i].fPendingIO) { fSuccess = GetOverlappedResult( Pipe[i].hPipeInst, // handle to pipe &Pipe[i].oOverlap, // OVERLAPPED structure &cbBytes, // bytes transferred FALSE); // do not wait switch (Pipe[i].dwState) { // Pending connect operation case CONNECTING_STATE:
if (! fSuccess) MyErrExit("ConnectNamedPipe"); Pipe[i].dwState = READING_STATE; break; // Pending read operation case READING_STATE: if (! fSuccess || cbBytes == 0) { DisconnectAndReconnect(i); continue; } Pipe[i].dwState = WRITING_STATE; break; // Pending write operation
case WRITING_STATE: if (! fSuccess || cbBytes != Pipe[i].cbToWrite) { DisconnectAndReconnect(i); continue; } Pipe[i].dwState = READING_STATE; break; default: MyErrExit("invalid pipe state"); } } // The pipe state determines which operation to do next. switch (Pipe[i].dwState)
{ // READING_STATE: // The pipe instance is connected to the client // and is ready to read a request from the client. case READING_STATE: fSuccess = ReadFile( Pipe[i].hPipeInst, Pipe[i].chBuf, BUFSIZE, &cbBytes, &Pipe[i].oOverlap); // The read operation completed successfully. if (fSuccess && cbBytes != 0)
{ Pipe[i].fPendingIO = FALSE; Pipe[i].dwState = WRITING_STATE; continue; } // The read operation is still pending dwErr = GetLastError(); if (! fSuccess && (dwErr == ERROR_IO_PENDING)) { Pipe[i].fPendingIO = TRUE; continue; } // An error occurred; disconnect from the client.
DisconnectAndReconnect(i); break; // WRITING_STATE: // The request was successfully read from the client. // Get the reply data and write it to the client. case WRITING_STATE: GetDataToWriteToClient(&Pipe[i]); fSuccess = WriteFile( Pipe[i].hPipeInst, Pipe[i].chBuf, Pipe[i].cbToWrite, &cbBytes, &Pipe[i].oOverlap);
// The write operation completed successfully. if (fSuccess && cbBytes == Pipe[i].cbToWrite) { Pipe[i].fPendingIO = FALSE; Pipe[i].dwState = READING_STATE; continue; } // The write operation is still pending. dwErr = GetLastError(); if (! fSuccess && (dwErr == ERROR_IO_PENDING)) { Pipe[i].fPendingIO = TRUE;
continue; } // An error occurred; disconnect from the client. DisconnectAndReconnect(i); break; default: MyErrExit("invalid pipe state"); } } return 0; } // DisconnectAndReconnect(DWORD) // This function is called when an error occurs or when the client // closes its handle to the pipe. Disconnect from this client, then // call ConnectNamedPipe to wait for another client to connect.
VOID DisconnectAndReconnect(DWORD i) { // Disconnect the pipe instance. if (! DisconnectNamedPipe(Pipe[i].hPipeInst) ) MyErrExit("DisconnectNamedPipe"); // Call a subroutine to connect to the new client. Pipe[i].fPendingIO = ConnectToNewClient( Pipe[i].hPipeInst, &Pipe[i].oOverlap); Pipe[i].dwState = Pipe[i].fPendingIO ? CONNECTING_STATE : // still connecting READING_STATE; // ready to read }
// ConnectToNewClient(HANDLE, LPOVERLAPPED) // This function is called to start an overlapped connect operation. // It returns TRUE if an operation is pending or FALSE if the // connection has been completed. BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo) { BOOL fConnected, fPendingIO = FALSE; // Start an overlapped connection for this pipe instance. fConnected = ConnectNamedPipe(hPipe, lpo); // Overlapped ConnectNamedPipe should return FALSE.
if (fConnected) MyErrExit("ConnectNamedPipe"); switch (GetLastError()) { // The overlapped connection in progress. case ERROR_IO_PENDING: fPendingIO = TRUE; break; // Client is already connected, so signal an event. case ERROR_PIPE_CONNECTED: if (SetEvent(lpo->hEvent)) break; // If an error occurs during the connect operation... default: MyErrExit("ConnectNamedPipe");
} return fPendingIO; }
| Пригласи друзей и счет твоего мобильника всегда будет положительным! |
| Пригласи друзей и счет твоего мобильника всегда будет положительным! |
Сервер, использовавший Перекрытый Ввод и Выход
Этот пример является единственный прошитым процессом сервера, который использует перекрытые операции, чтобы обслуживать одновременные связи во многочисленные процессы клиента. Процесс сервера создает фиксированный номер примеров трубы, которая может быть подключена к отдельному процессу клиента. Когда процесс клиента завершил использование примера трубы, сервер отключает от клиента и ответчиков пример трубы, чтобы подключать к новому клиенту.
Связанное каждым примером трубы - ПЕРЕКРЫТАЯ структура, содержащая объект события. Эта структура определена как параметр на каждой ReadFile, WriteFile, и операции ConnectNamedPipe в примере трубы. Хотя пример показывает одновременные операции в других примерах трубы, он избегает одновременных операций в единственном примере трубы. Поскольку тот же объект события использован для чтения, запишите, и соединяют операции для каждого примера, нет пути знать какую операцию завершения вызвавшую событие, которое нужно быть установлено в сигнальное состояние для одновременных операций, использовавших тот же пример трубы.
Ручки события для каждого примера трубы также загружены в массив использованный функцией WaitForMultipleObjects. Эта функция ждет одно из событий, которые нужно сигнализировать, и обратная величина является индексом массива события, который удовлетворял ожидание. Пример использует этот индекс, чтобы извлекать структуру, содержащую информацию для примера трубы. Сервер использует элемент fPendingIO структуры, чтобы следить независимо наиболее последней операции В/В в примере рассматривался, требующий вызов в функцию GetOverlappedResult. Это использует элемент dwState структуры, чтобы определять следующую операцию, которая должна быть выполнена для примера.
Перекрытые ReadFile, WriteFile, и операции ConnectNamedPipe могут завершиться когда функция возвращается, или они могут все еще рассматривать когда функция возвращается. Если операция рассматривается, объект события в определенной ПЕРЕКРЫТОЙ структуре установлен в nonsignaled состояние прежде, чем функция возвращается. Когда незаконченная операция завершилась, система устанавливает состояние объекта события против сигнального. Состояние объекта события не измениться если операция завершается прежде, чем функция возвращается.
Поскольку пример использует руководство восстановившее событие возражает, состояние объектов события не изменено на nonsignaled функцией WaitForMultipleObjects. Важно, поскольку пример доверяется на объекты события, остающиеся в сигнальном состоянии кроме когда есть незаконченная операция. Если операция уже завершена когда ReadFile, WriteFile, или возврат ConnectNamedPipe, функциональная обратная величина указывает результат. Для чтения и операций записи, количество переданных байтов также возвращано. Если операция все еще рассматривается, ReadFile, WriteFile, или функциональная ЛОЖЬ возврата ConnectNamedPipe и функциональный возврат GetLastError ERROR_IO_PENDING. В этом случае, результаты извлечены используя GetOverlappedResult функционирует после того, как операция завершилась. GetOverlappedResult ВОЗВРАЩАЕТ только результаты операций, которые рассматривали, и не сообщают результаты операций, которые были завершены прежде, чем перекрытая ReadFile, WriteFile, или функция ConnectNamedPipe возвращалась.
Перед отключением от клиента, multithreaded пример сервера в предшествующей секции использовал FlushFileBuffers, чтобы проверять, что клиент прочитал весь записанный в трубу. Это должно побеждать цель перекрытого В/В, поскольку операция краски должна блокировать выполнение резьбы сервера тогда как она ждет клиента на пустой труба. Следовательно, необходимо должно ждать сигнал из клиента, который это завершило перед отключением. В этом примере, сигнал является ошибкой сгенерированной попыткой, чтобы читаться из трубы после того, как процесс клиента закроет свою ручку.
#include <окно.h> #define CONNECTING_STATE 0 #define READING_STATE 1 #define WRITING_STATE 2 ПРИМЕРОВ #define 4 typedef struct { ПЕРЕКРЫВШЕЕ oOverlap; ПРООПЕРИРУЙТЕ hPipeInst; СИМВОЛ chBuf[BUFSIZE]; DWORD cbToWrite; DWORD dwState; BOOL fPendingIO; } PIPEINST, *LPPIPEINST; АННУЛИРУЙТЕ DisconnectAndReconnect(DWORD); BOOL ConnectToNewClient(РУЧКА, LPOVERLAPPED); АННУЛИРУЙТЕ GetDataToWriteToClient(LPPIPEINST); ТРУБА PIPEINST[INSTANCES];
ПРООПЕРИРУЙТЕ hEvents[INSTANCES]; ОСНОВА DWORD(ПУСТОТА) { DWORD Я, dwWait, cbBytes, dwErr; BOOL fSuccess; LPTSTR lpszPipename = "\\\\.\\pipe\\mynamedpipe"; // Начальный цикл создает несколько примеров поименованной трубы // вместе с объектом события для каждого примера. // Перекрывшее операцию ConnectNamedPipe запущен для // каждого примера. для (i = 0; я < ПРИМЕРЫ; я++) { // Создайте объект события для этого примера. hEvents[i] = CreateEvent(
НЕДЕЙСТВИТЕЛЬНАЯ, // никакая вспомогательная ИСТИНА безопасности, // руководства-не была восстановлена ИСТИНА события, // инициала указывать = сигнализировавшее НЕДЕЙСТВИТЕЛЬНЫМ); // безымянный объект события если (hEvents[i] == НЕДЕЙСТВИТЕЛЬНЫЙ) MyErrExit("CreateEvent"); Труба[i].oOverlap.hEvent = hEvents[i]; Труба[i].hPipeInst = CreateNamedPipe( lpszPipename, // имя трубы PIPE_ACCESS_DUPLEX | // прочитавшее/доступ записи FILE_FLAG_OVERLAPPED, // перекрытого режима
PIPE_TYPE_MESSAGE | // сообщение-тип трубы PIPE_READMODE_MESSAGE | // сообщение-было прочитано режим PIPE_WAIT, // ПРИМЕРЫ режима блокировки, // количество примеров BUFSIZE, // выходной буферный размер BUFSIZE, // входной буферный размер PIPE_TIMEOUT, // задержка клиента НЕДЕЙСТВИТЕЛЬНЫЙ); // никакая безопасность не приписывается если (Труба[i].hPipeInst == INVALID_HANDLE_VALUE)
MyErrExit("CreatePipe"); // Вызов подпрограмма, чтобы подключать к новому клиенту Труба[i].fPendingIO = ConnectToNewClient( Труба[i].hPipeInst, &Труба[i].oOverlap); Труба[i].dwState = Труба[i].fPendingIO? CONNECTING_STATE : // все еще соединяя READING_STATE; // готовый прочитаться } пока (1) { // Ожидание объект события против сигнализирован, указание // завершение перекрытого чтения, записи, или
// соедините операцию. dwWait = WaitForMultipleObjects( ПРИМЕРЫ, // номер объектов события hEvents, // массив события возражает ЛЖИ, // не ждет весь БЕСКОНЕЧНЫЙ); // ожидания неопределенно // dwWait Показывает какую трубу завершившую операцию. я = dwWait - WAIT_OBJECT_0; // определяет какую трубу если (я < 0 || я > (ПРИМЕРЫ - 1)) MyErrExit("index из дипазона");
// Получите результат если операция рассматривалась бы. если (Труба[i].fPendingIO) { fSuccess = GetOverlappedResult( Труба[i].hPipeInst, // ручка в трубу &Трубу[i].oOverlap, // ПЕРЕКРЫТАЯ структура &cbBytes, // байты передавали ЛОЖЬ); // не ожидайтесь ключ (Труба[i].dwState) { // Рассматривать соединяет операцию случая CONNECTING_STATE:
если (! fSuccess) MyErrExit("ConnectNamedPipe"); Труба[i].dwState = READING_STATE; прерывание; // Рассматривать было прочитано операция случая READING_STATE: если (! fSuccess || cbBytes == 0) { DisconnectAndReconnect(i); останьтесь; } Труба[i].dwState = WRITING_STATE; прерывание; // Рассматривать операции записи
случай WRITING_STATE: если (! fSuccess || cbBytes != Труба[i].cbToWrite) { DisconnectAndReconnect(i); останьтесь; } Труба[i].dwState = READING_STATE; прерывание; умолчание: MyErrExit(СОСТОЯНИЕ "invalid трубы"); } } // Состояние трубы определяет какую операцию, чтобы делать затем. ключ (Труба[i].dwState)
{ // READING_STATE: // Пример трубы подключен к клиенту // и готовый прочитать запрос из клиента. случай READING_STATE: fSuccess = ReadFile( Труба[i].hPipeInst, Труба[i].chBuf, BUFSIZE, &cbBytes, &Труба[i].oOverlap); // Операция чтения завершалась успешно. если (fSuccess && cbBytes != 0)
{ Труба[i].fPendingIO = ЛОЖЬ; Труба[i].dwState = WRITING_STATE; останьтесь; } // Операция чтения все еще рассматривается dwErr = GetLastError(); если (! fSuccess && (dwErr == ERROR_IO_PENDING)) { Труба[i].fPendingIO = ИСТИНА; останьтесь; } // Ошибка происходила; отключите от клиента.
DisconnectAndReconnect(i); прерывание; // WRITING_STATE: // Запрос успешно был прочитан из клиента. // Получите данные ответа и записывайте это клиенту. случай WRITING_STATE: GetDataToWriteToClient(&Pipe[i]); fSuccess = WriteFile( Труба[i].hPipeInst, Труба[i].chBuf, Труба[i].cbToWrite, &cbBytes, &Труба[i].oOverlap);
// Записывать операция завершалась успешно. если (fSuccess && cbBytes == Труба[i].cbToWrite) { Труба[i].fPendingIO = ЛОЖЬ; Труба[i].dwState = READING_STATE; останьтесь; } // Записывать операция все еще рассматривается. dwErr = GetLastError(); если (! fSuccess && (dwErr == ERROR_IO_PENDING)) { Труба[i].fPendingIO = ИСТИНА;
останьтесь; } // Ошибка происходила; отключите от клиента. DisconnectAndReconnect(i); прерывание; умолчание: MyErrExit(СОСТОЯНИЕ "invalid трубы"); } } возврат 0; } // DisconnectAndReconnect(DWORD) // ЭТА функция вызвана когда ошибка происходит или когда клиент // закрывает свою ручку в трубу. Отключите от этого клиента, затем // вызова ConnectNamedPipe, чтобы ждать другого клиента, чтобы соединяться.
ПУСТОТА DisconnectAndReconnect(DWORD я) { // Разъедините пример трубы. если (! DisconnectNamedPipe(ТРУБА[i].hPipeInst) ) MyErrExit("DisconnectNamedPipe"); // Вызов подпрограмма, чтобы подключать к новому клиенту. Труба[i].fPendingIO = ConnectToNewClient( Труба[i].hPipeInst, &Труба[i].oOverlap); Труба[i].dwState = Труба[i].fPendingIO? CONNECTING_STATE : // все еще соединяя READING_STATE; // готовый прочитаться }
// ConnectToNewClient(РУЧКА, LPOVERLAPPED) // Эта функция вызвана, чтобы запускать перекрытый соединять операцию. // Это возвращает ИСТИНУ если операция рассматривает или ЛОЖЬ если // связь завершена. BOOL ConnectToNewClient(РУЧКА hPipe, LPOVERLAPPED lpo) { BOOL fConnected, fPendingIO = ЛОЖЬ; // Запустите перекрытую связь для этого примера трубы. fConnected = ConnectNamedPipe(hPipe, lpo); // Перекрывшее ConnectNamedPipe должен возвращать ЛОЖЬ.
если (fConnected) MyErrExit("ConnectNamedPipe"); ключ (GetLastError()) { // Перекрытая связь в процессе развития. случай ERROR_IO_PENDING: fPendingIO = ИСТИНА; прерывание; // Клиент уже связан, так что сигнализировать событие. случай ERROR_PIPE_CONNECTED: если прерывание (SetEvent(lpo->hEvent)); // Если ошибка происходит в течение соединять операцию... умолчание: MyErrExit("ConnectNamedPipe");
} возвращайте fPendingIO; }
|
|
|
|
| |