接続指向ソケット経由でのデータの受信
Winsock カーネル (WSK) アプリケーションが接続指向ソケットをリモート トランスポート アドレスに接続した後、ソケット経由でデータを受信できます。 WSK アプリケーションは、リッスンしているソケットで受け入れた接続指向ソケット経由でデータを受信することもできます。 WSK アプリケーションは、WskReceive 関数を呼び出して、接続指向ソケット経由でデータを受信します。
次のコード例は、WSK アプリケーションが接続指向ソケット経由でデータを受信する方法を示しています。
// Prototype for the receive IoCompletion routine
NTSTATUS
ReceiveComplete(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
);
// Function to receive data
NTSTATUS
ReceiveData(
PWSK_SOCKET Socket,
PWSK_BUF DataBuffer
)
{
PWSK_PROVIDER_CONNECTION_DISPATCH Dispatch;
PIRP Irp;
NTSTATUS Status;
// Get pointer to the provider dispatch structure
Dispatch =
(PWSK_PROVIDER_CONNECTION_DISPATCH)(Socket->Dispatch);
// Allocate an IRP
Irp =
IoAllocateIrp(
1,
FALSE
);
// Check result
if (!Irp)
{
// Return error
return STATUS_INSUFFICIENT_RESOURCES;
}
// Set the completion routine for the IRP
IoSetCompletionRoutine(
Irp,
ReceiveComplete,
DataBuffer, // Use the data buffer for the context
TRUE,
TRUE,
TRUE
);
// Initiate the receive operation on the socket
Status =
Dispatch->WskReceive(
Socket,
DataBuffer,
0, // No flags are specified
Irp
);
// Return the status of the call to WskReceive()
return Status;
}
// Receive IoCompletion routine
NTSTATUS
ReceiveComplete(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
)
{
UNREFERENCED_PARAMETER(DeviceObject);
PWSK_BUF DataBuffer;
ULONG ByteCount;
// Check the result of the receive operation
if (Irp->IoStatus.Status == STATUS_SUCCESS)
{
// Get the pointer to the data buffer
DataBuffer = (PWSK_BUF)Context;
// Get the number of bytes received
ByteCount = (ULONG)(Irp->IoStatus.Information);
// Process the received data
...
}
// Error status
else
{
// Handle error
...
}
// Free the IRP
IoFreeIrp(Irp);
// Always return STATUS_MORE_PROCESSING_REQUIRED to
// terminate the completion processing of the IRP.
return STATUS_MORE_PROCESSING_REQUIRED;
}
WSK アプリケーションは、WskReceive 関数を呼び出して接続指向ソケット経由でデータを受信する代わりに、ソケットで WskReceiveEvent イベント コールバック関数を有効にすることができます。 WSK アプリケーションが接続指向ソケットで WskReceiveEvent イベント コールバック関数を有効にした場合、WSK サブシステムは、ソケットで新しいデータを受信するたびに、ソケットの WskReceiveEvent イベント コールバック関数を呼び出します。 接続指向ソケットの WskReceiveEvent イベント コールバック関数を有効にする方法について詳しくは、「イベント コールバック関数の有効化と無効化」をご覧ください。
次のコード例は、接続指向ソケットの WskReceiveEvent イベント コールバック関数を呼び出す WSK サブシステムにより WSK アプリケーションがデータを受信する方法を示しています。
// A connection-oriented socket's WskReceiveEvent
// event callback function
NTSTATUS WSKAPI
WskReceiveEvent(
PVOID SocketContext,
ULONG Flags,
PWSK_DATA_INDICATION DataIndication,
SIZE_T BytesIndicated,
SIZE_T *BytesAccepted
)
{
// Check for a valid data indication
if (DataIndication != NULL)
{
// Loop through the list of data indication structures
while (DataIndication != NULL)
{
// Process the data in the data indication structure
...
// Move to the next data indication structure
DataIndication = DataIndication->Next;
}
// Return status indicating the data was received
return STATUS_SUCCESS;
}
// Error
else
{
// Close the socket
...
// Return success since no data was indicated
return STATUS_SUCCESS;
}
}
接続指向ソケットの WskReceiveEvent イベント コールバック関数が、DataIndication パラメーターによってポイントされる WSK_DATA_INDICATION 構造のリストに含まれるデータをすべては取得しない場合、STATUS_PENDING を返すことによって、さらに処理するためにリストを保持できます。 このような場合、WSK アプリケーションは、wskRelease 関数を呼び出して、リスト内の構造からすべてのデータの取得が完了した後、WSK_DATA_INDICATION 構造のリストを WSK サブシステムに解放する必要があります。
接続指向ソケットの WskReceiveEvent イベント コールバック関数が受信したデータの合計バイト数の一部のみ受け入れる場合は、BytesAccepted パラメーターによってポイントされる変数を、実際に受け入れられたデータのバイト数に設定する必要があります。 ただし、ソケットの WskReceiveEvent イベント コールバック関数が受信したデータをすべて受け入れる場合、BytesAccepted パラメーターによってポイントされる変数を設定する必要はありません。