Server Pipa Bernama menggunakan I/O yang Tumpang Tindih
Berikut ini adalah contoh server pipa berulir tunggal yang menggunakan operasi tumpang tindih untuk melayani koneksi simultan ke beberapa klien pipa. Server pipa membuat sejumlah instans pipa tetap. Setiap instans pipa dapat dihubungkan ke klien pipa terpisah. Ketika klien pipa telah selesai menggunakan instans pipanya, server terputus dari klien dan menggunakan kembali instans pipa untuk terhubung ke klien baru. Server pipa ini dapat digunakan dengan klien pipa yang dijelaskan dalam Named Pipe Client.
Struktur TUMPANG TINDIH ditentukan sebagai parameter di setiap operasi ReadFile, WriteFile, dan ConnectNamedPipe pada instans pipa. Meskipun contoh menunjukkan operasi simultan pada instans pipa yang berbeda, contoh ini menghindari operasi simultan pada satu instans pipa dengan menggunakan objek peristiwa dalam struktur YANG TUMPANG TINDIH . Karena objek peristiwa yang sama digunakan untuk operasi baca, tulis, dan sambungkan untuk setiap instans, tidak ada cara untuk mengetahui penyelesaian operasi mana yang menyebabkan peristiwa diatur ke status sinyal untuk operasi simultan menggunakan instans pipa yang sama.
Penanganan peristiwa untuk setiap instans pipa disimpan dalam array yang diteruskan ke fungsi WaitForMultipleObjects . Fungsi ini menunggu salah satu peristiwa disinyalkan, dan mengembalikan indeks array peristiwa yang menyebabkan operasi tunggu selesai. Contoh dalam topik ini menggunakan indeks array ini untuk mengambil struktur yang berisi informasi untuk instans pipa. Server menggunakan anggota fPendingIO dari struktur untuk melacak apakah operasi I/O terbaru pada instans tertunda, yang memerlukan panggilan ke fungsi GetOverlappedResult . Server menggunakan anggota dwState dari struktur untuk menentukan operasi berikutnya yang harus dilakukan untuk instans pipa.
Operasi ReadFile, WriteFile, dan ConnectNamedPipe yang tumpang tindih dapat selesai pada saat fungsi kembali. Jika tidak, jika operasi tertunda, objek peristiwa dalam struktur TUMPANG TINDIH yang ditentukan diatur ke status tidak bertanda sebelum fungsi kembali. Ketika operasi tertunda selesai, sistem mengatur status objek peristiwa ke sinyal. Status objek peristiwa tidak diubah jika operasi selesai sebelum fungsi kembali.
Karena contoh menggunakan objek peristiwa reset manual, status objek peristiwa tidak diubah menjadi tidak ditandatangani oleh fungsi WaitForMultipleObjects . Ini penting, karena contohnya bergantung pada objek peristiwa yang tersisa dalam status disinyalkan, kecuali ketika ada operasi yang tertunda.
Jika operasi telah selesai saat ReadFile, WriteFile, atau ConnectNamedPipe mengembalikan, nilai pengembalian fungsi menunjukkan hasilnya. Untuk operasi baca dan tulis, jumlah byte yang ditransfer juga dikembalikan. Jika operasi masih tertunda, fungsi ReadFile, WriteFile, atau ConnectNamedPipe mengembalikan nol dan fungsi GetLastError mengembalikan ERROR_IO_PENDING. Dalam hal ini, gunakan fungsi GetOverlappedResult untuk mengambil hasil setelah operasi selesai. GetOverlappedResult hanya mengembalikan hasil operasi yang tertunda. Ini tidak melaporkan hasil operasi yang diselesaikan sebelum fungsi ReadFile, WriteFile, atau ConnectNamedPipe yang tumpang tindih dikembalikan.
Sebelum memutuskan sambungan dari klien, Anda harus menunggu sinyal yang menunjukkan klien telah selesai. (Membersihkan buffer file akan mengalahkan tujuan I/O yang tumpang tindih, karena operasi flush akan memblokir eksekusi utas server sambil menunggu klien mengosongkan pipa.) Dalam contoh ini, sinyal adalah kesalahan yang dihasilkan dengan mencoba membaca dari pipa setelah klien pipa menutup handelnya.
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>
#define CONNECTING_STATE 0
#define READING_STATE 1
#define WRITING_STATE 2
#define INSTANCES 4
#define PIPE_TIMEOUT 5000
#define BUFSIZE 4096
typedef struct
{
OVERLAPPED oOverlap;
HANDLE hPipeInst;
TCHAR chRequest[BUFSIZE];
DWORD cbRead;
TCHAR chReply[BUFSIZE];
DWORD cbToWrite;
DWORD dwState;
BOOL fPendingIO;
} PIPEINST, *LPPIPEINST;
VOID DisconnectAndReconnect(DWORD);
BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED);
VOID GetAnswerToRequest(LPPIPEINST);
PIPEINST Pipe[INSTANCES];
HANDLE hEvents[INSTANCES];
int _tmain(VOID)
{
DWORD i, dwWait, cbRet, dwErr;
BOOL fSuccess;
LPCTSTR lpszPipename = TEXT("\\\\.\\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, // default security attribute
TRUE, // manual-reset event
TRUE, // initial state = signaled
NULL); // unnamed event object
if (hEvents[i] == NULL)
{
printf("CreateEvent failed with %d.\n", GetLastError());
return 0;
}
Pipe[i].oOverlap.hEvent = hEvents[i];
Pipe[i].oOverlap.Offset = 0;
Pipe[i].oOverlap.OffsetHigh = 0;
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*sizeof(TCHAR), // output buffer size
BUFSIZE*sizeof(TCHAR), // input buffer size
PIPE_TIMEOUT, // client time-out
NULL); // default security attributes
if (Pipe[i].hPipeInst == INVALID_HANDLE_VALUE)
{
printf("CreateNamedPipe failed with %d.\n", GetLastError());
return 0;
}
// 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))
{
printf("Index out of range.\n");
return 0;
}
// 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
&cbRet, // bytes transferred
FALSE); // do not wait
switch (Pipe[i].dwState)
{
// Pending connect operation
case CONNECTING_STATE:
if (! fSuccess)
{
printf("Error %d.\n", GetLastError());
return 0;
}
Pipe[i].dwState = READING_STATE;
break;
// Pending read operation
case READING_STATE:
if (! fSuccess || cbRet == 0)
{
DisconnectAndReconnect(i);
continue;
}
Pipe[i].cbRead = cbRet;
Pipe[i].dwState = WRITING_STATE;
break;
// Pending write operation
case WRITING_STATE:
if (! fSuccess || cbRet != Pipe[i].cbToWrite)
{
DisconnectAndReconnect(i);
continue;
}
Pipe[i].dwState = READING_STATE;
break;
default:
{
printf("Invalid pipe state.\n");
return 0;
}
}
}
// 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].chRequest,
BUFSIZE*sizeof(TCHAR),
&Pipe[i].cbRead,
&Pipe[i].oOverlap);
// The read operation completed successfully.
if (fSuccess && Pipe[i].cbRead != 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:
GetAnswerToRequest(&Pipe[i]);
fSuccess = WriteFile(
Pipe[i].hPipeInst,
Pipe[i].chReply,
Pipe[i].cbToWrite,
&cbRet,
&Pipe[i].oOverlap);
// The write operation completed successfully.
if (fSuccess && cbRet == 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:
{
printf("Invalid pipe state.\n");
return 0;
}
}
}
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) )
{
printf("DisconnectNamedPipe failed with %d.\n", GetLastError());
}
// 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 zero.
if (fConnected)
{
printf("ConnectNamedPipe failed with %d.\n", GetLastError());
return 0;
}
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:
{
printf("ConnectNamedPipe failed with %d.\n", GetLastError());
return 0;
}
}
return fPendingIO;
}
VOID GetAnswerToRequest(LPPIPEINST pipe)
{
_tprintf( TEXT("[%d] %s\n"), pipe->hPipeInst, pipe->chRequest);
StringCchCopy( pipe->chReply, BUFSIZE, TEXT("Default answer from server") );
pipe->cbToWrite = (lstrlen(pipe->chReply)+1)*sizeof(TCHAR);
}
Topik terkait
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk