勇敢心资源网

当前位置:首页 > 百科 / 正文

winsock kernel

(2021-06-27 23:09:10) 百科

winsock kernel

winsock kernel支持多种类型的传输协定,WSK对象是client 和 socket。

基本介绍

  • 外文名:winsock kernel
  • 核心:WSK子系统
  • WSK对象:client 和 socket
  • 支持:多种类型的传输协定

WSK架构

WSK架构的核心是WSK子系统.WSK子系统是一个网路模组,它实现了WSK网路编程接口(NPI)的提供端(provider side)。WSK子系统接口在它的下层有传输接口,它支持多种类型的传输协定。
绑定在WSK子系统上的是WSK程式。WSK程式是核心模式的软体模组,为了展示了网路IO操作,它们实现了WSK NPI的客户端。(在此处,“客户”不应和客户-伺服器系统中的“客户”相混淆)WSK子系统可以调用WSK客户NPI函式来通知WSK程式异步事件的到来。 WSK程式通过一组WSK注册函式找到(discover)并绑定到WSK子系统。WSK程式可以通过使用这些函式在WSK子系统可用时动态检测到它,并交换提供者和WSK NPI客户端实现的派遣表。and to exchange dispatch tables that constitute the provider and client side implementations of the WSK NPI.
winsock kernel
WSK程式可以使用网路模组注册(Network Module Registrar (NMR))绑定到WSK子系统。更多信息,参考“使用NMR实现WSK的注册和注销”Using NMR for WSK Registration and Unregistration.

WSK对象

Winsock 核心NPI围绕两个主要的对象类型来设计:client 和 socket。

客户对象(Client Object)

一个client对象代表了一个WSK程式和WSK子系统间的依附或者绑定。一个Client对象 由一个WSK_CLIENT结构代表。一个指向客户对象的指针在WSK程式绑定到WSK子系统时获得。WSK程式传递这个指针给在这个客户对象层面上操作的所有WSK函式。

套接字对象(Socket Object)

一个socket对象代表了一个可以用于网路I/O的网路套接字。一个Socket对象由一个WSK_SOCKET结构代表。一个指向套接字对象的指针在WSK程式接收一个进来的(incoming)连线时获得。WSK程式传递这个指针给仅限于某个特定套接字的所有WSK函式。

WSK套接字类别

Winsock核心NPI定义了四种不同的套接字类别:基本套接字,监听套接字,数据包套接字,基于连线的套接字。每个WSK套接字类别有特有的功能并支持不同的套接字函式集合。WSK程式必须在它创建一个新套接字对象时指定类别。每个WSK套接字类别的用途如下:

基本套接字

基本套接字(Basic Sockets)只用于获取和设定传输堆叠的套接字选项,或者实现套接字IO控制操作。基本套接字不能绑定到本地的传输地址而且不能支持收发网路数据。

监听套接字

监听套接字(Listening Sockets)用于监听远端(remote)传输地址的进入(incoming)连线。监听套接字的功能包含所有基本套接字的功能。

数据包套接字

数据包套接字(Datagram Sockets)用于收发数据包(datagram)。数据包套接字的功能包含所有基本套接字的功能。

基于连线的套接字

基于连线的套接字(Connection-Oriented Sockets)用于在已建立的连线上收发网路数据。基于连线的套接字的功能包含所有基本套接字的功能。

使用WSK核心函式

WSK程式驱动套接字操作,也就是说当套接字造作发生时WSK程式开始控制。这会简化WSK程式所请求的的同步。WSK程式给套接字函式提供IRP。这些IRP被WSK子系统排队,直到套接字操作完成。更多关于WSK函式中使用IRP的信息,参考“WSK函式中使用IRP”(Using IRPs with Winsock Kernel Functions)。WSK程式可以实现阻塞套接字操作,通过等待IRP的每个操作都被WSK子系统完成。WSK程式可能需要进行多个在某些情况下排队的套接字操作,为了在基于连线的套接字中确保有好的数据传输表现,为了在数据包套接字中防止数据包被丢弃,或者为了在监听套接字中防止进入的连线被丢弃。WSK程式为数据传输操作提供数据缓冲区。这减少了数据被拷贝的次数。然而,如果一个WSK程式进行多个排队的数据传输操作,它必须为每个排队的数据传输操作提供数据缓冲区给WSK子系统。

使用事件回调函式

WSK子系统驱动套接字操作,意思是WSK子系统通过调用套接字的事件回调函式通知WSK程式套接字事件。WSK程式可能需要更複杂的同步来处理事件回调函式的异步特徵。WSK程式在套接字操作中不适用IRPs。WSK程式不需要排队套接字操作。WSK子系统在套接字事件发生时,立刻调用WSK程式的事件回调函式。如果WSK程式可以与套接字事件回调函式被调用的进度持平,使用事件回调函式何以提供最好的表现和最小丢失数据包和进入的连线的机会。WSK子系统为数据传输操作提供数据缓冲区。WSK程式必须立刻或者在一个合理的时间内释放这些数据缓冲区给WSK子系统,这可以避免WSK子系统用完存储资源。因此,WSK程式可能需要把数据从WSK子系统拥有的数据缓冲区拷贝到它自己的数据缓冲区。

WSK“扩展接口”

WSK NPI支持扩展接口。WSK子系统可以通过使用“扩展接口”扩展WSK套接字的功能,是它不仅限于WSK NPI当前定义的套接字功能集和事件回调函式。每个NPI定义的扩展接口与WSK NPI无关。当前还没有没有定义扩展接口。
WSK程式可以通过使用SIO_WSK_REGISTER_EXTENSION套接字IOCTL操作注册一个被WSK子系统支持的设备扩展。
更多关于注册扩展接口的信息,参考“注册一个设备扩展” (Registering an Extension Interface)。

在Winsock核心函式中使用IRP

WSK NPI使用IRP实现网路I/O操作的异步完成。IRP的指针作为每个WSK函式的一个参数。WSK子系统在WSK函式完成操作后完成此IRP。
WSK程式用来传递到一个WSK函式中的IRP可以源于以下方法。
WSK程式调用IoAllocateIrp分配这个IRP。这种情况下,WSK程式必须给这个IRP分配至少一个I/O堆叠单元。WSK程式重新使用一个先前分配但已完成的IRP。WSK必须调用IoReuseIrp来重新初始化这个IRP。WSK程式使用从上层或I/O管理器传到它的IRP。这种情况,此IRP必须有至少一个IO堆叠单元供WSK子系统使用。
在WSK程式拥有一个IRP来调用WSK函式后,它可以为此IRP设定一个完成例程,当WSK子系统完成IRP时此例程被调用。WSK程式通过调用IoSetCompletionRoutine来为IRP设定完成例程。IoCompletion routine需要或可选,取决于这个IRP是如何产生的。
如果WSK程式分配此IRP,或者重用它先前分配的IRP,那幺它必须在调用WSK函式前设定一个完成例程。这种情况下,必须把传递给IoCompletion routine的参数InvokeOnSuccess, InvokeOnError, and InvokeOnCancel都设为TRUE,以确保IoCompletion routine总是被调用。而且,此IRP的IoCompletion routine必须总是返回STATUS_MORE_PROCESSING_REQUIRED来结束此IRP的完成处理。If the WSK application is done using the IRP after the IoCompletion routine has been called, then it should call the IoFreeIrp function to free the IRP before returning from the IoCompletion routine.如果WSK程式。如果WSK程式没有释放这个IRP,那幺它可以在调用其它的WSK函式时重用这个IRP。如果WSK程式使用一个从高层驱动或IO管理器传递下来的IRP,仅当它在WSK函式完成操作后必须被通知时,它需要在调用WSK函式前设定完成例程。如果WSK程式没有为此IRP设定完成例程,当此IRP被完成时,它会像每个正常IRP的完成处理那样被传递至上层驱动或IO管理器。如果WSK程式设定了一个完成例程,这个完成例程可以返回STATUS_SUCCESS或STATUS_MORE_PROCESSING_REQUIRED。如果完成例程返回了STATUS_SUCCESS,这个IRP的完成处理会正常地继续下去。如果完成例程返回了STATUS_MORE_PROCESSING_REQUIRED,WSK程式必须在它完成WSK函式处理的操作完成之后调用函式IoCompleteRequest来完成此IRP。WSK程式不能释放从高层驱动或IO管理器传给它的IRP。
注意:如果WSK程式为由上层驱动或IO管理器传递过来的且传至下层的IRP设定了一个完成例程,那幺完成例程必须检查IRP的PendingReturned位,如果PendingReturned是TRUE的话,它必须调用IoMarkIrpPending。更多信息,参考“实现一个完成例程” Implementing an IoCompletion Routine。
WSK程式不初始化它传递至WSK函式的IRP,除了设定一个完成例程。当WSK程式传递一个IRP到WSK函式时,WSK子系统代表WSA程式设定下一堆叠单元。
下面的代码示例显示了WSK程式在一个套接字上进行接收操作时如何分配和使用IRP。
// 接受完成例程的原型
NTSTATUS
ReceiveComplete(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
);
// 接收数据的函式
NTSTATUS
ReceiveData(
PWSK_SOCKET Socket,
PWSK_BUF DataBuffer
)
{
PWSK_PROVIDER_CONNECTION_DISPATCH Dispatch;
PIRP Irp;
NTSTATUS Status;
// 获取“供应者派遣结构指针”
Dispatch =
(PWSK_PROVIDER_CONNECTION_DISPATCH)(Socket->Dispatch);
// 分配一个IRP
Irp =
IoAllocateIrp(
1,
FALSE
);
// Check result
if (!Irp)
{
// 返回错误
return STATUS_INSUFFICIENT_RESOURCES;
}
// 设定此IRP的完成例程
IoSetCompletionRoutine(
Irp,
ReceiveComplete,
DataBuffer, // 数据缓冲区作为上下文
TRUE,
TRUE,
TRUE
);
// 初始化这个套接字的接收操作
Status =
Dispatch->WskReceive(
Socket,
DataBuffer,
0, // 没有指定标誌
Irp
);
// 返回WskReceive的状态
return Status;
}
// 接收完成例程
NTSTATUS
ReceiveComplete(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
)
{
UNREFERENCED_PARAMETER(DeviceObject);
PWSK_BUF DataBuffer;
ULONG ByteCount;
// 检查接收操作的结果
if (Irp->IoStatus.Status == STATUS_SUCCESS)
{
// 获取数据缓冲区的指针
DataBuffer = (PWSK_BUF)Context;
// 获取接收的位元组数
ByteCount = (ULONG)(Irp->IoStatus.Information);
// 处理接收的数据
...
}
// 错误状态
else
{
// 处理错误
...
}
// 释放IRP
IoFreeIrp(Irp);
// 一直返回STATUS_MORE_PROCESSING_REQUIRED 来
// 结束IRP的完成处理
return STATUS_MORE_PROCESSING_REQUIRED;
}
在上面例子显示的模型中,WSK程式分配IRP并在完成例程里释放它。在余下的WSK文档中的例子使用了这个模型。
下面的代码示例显示了,在套接字上实现接受操作时,WSK程式可以使用上层驱动或IO管理器传递给它的IRP,当
// 接收完成例程的原型
NTSTATUS
ReceiveComplete(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
);
//接收数据的函式
NTSTATUS
ReceiveData(
PWSK_SOCKET Socket,
PWSK_BUF DataBuffer,
PIRP Irp; //从上层驱动或IO管理器传递下来的Irp
)
{
PWSK_PROVIDER_CONNECTION_DISPATCH Dispatch;
NTSTATUS Status;
// 获取“供应者派遣表”的指针
Dispatch =
(PWSK_PROVIDER_CONNECTION_DISPATCH)(Socket->Dispatch);
// 设定IRP的完成例程,仅当接收操作成功后被调用
IoSetCompletionRoutine(
Irp,
ReceiveComplete,
DataBuffer, // 数据缓冲区作为上下文
TRUE,
FALSE,
FALSE
);
// 在套接字上初始化接收操作
Status =
Dispatch->WskReceive(
Socket,
DataBuffer,
0, // 未指定标誌
Irp
);
// 返回 WskReceive()的状态码
return Status;
}
// 接收完成例程
NTSTATUS
ReceiveComplete(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
)
{
UNREFERENCED_PARAMETER(DeviceObject);
PWSK_BUF DataBuffer;
ULONG ByteCount;
// 因为完成例程只在操作完成时调用,所以这个永远是TRUE
ASSERT(Irp->IoStatus.Status == STATUS_SUCCESS);
// 检查这个IRP的pending状态
if (Irp->PendingReturned == TRUE)
{
// 标记这个IRP为pending
IoMarkIrpPending(Irp);
}
// 获取数据缓冲区的指针
DataBuffer = (PWSK_BUF)Context;
// 获取接收的位元组数
ByteCount = (ULONG)(Irp->IoStatus.Information);
// 处理接收的数据
...
// 返回STATUS_SUCCESS继续此IRP的完成处理
return STATUS_SUCCESS;
}
更多关于使用IRP的信息,参考“处理IRP” Handling IRPs。
声明:此文信息来源于网络,登载此文只为提供信息参考,并不用于任何商业目的。如有侵权,请及时联系我们:baisebaisebaise@yeah.net
搜索
随机推荐

勇敢心资源网|豫ICP备19027550号