Winsock Kernel Overview
本章節提供Winsock Kernel(WSK)的概觀以及下列的主題:
- Using Winsock Kernel Functions vs. Event Callback Functions
- Winsock Kernel Dispatch Tables
- Winsock Kernel Extension Interfaces
- Using IRPs with Winsock Kernel Functions
Using Winsock Kernel Functions vs. Event Callback Functions
對於某些 socket 操作,Winsock Kernel(WSK)應用程式可以調用socket的 WSK 函式來執行操作或是實作以及致能事件回呼函式(當event相關聯的操作發生時,WSK 子系統可以調用並且通知 WSK 應用程式)。舉例來說,要在連線導向(connection-oriented)socket上接收數據,WSK 應用程式可以選擇調用socket的WskReceive或是實作一個WskReceiveEvent事件回呼函式。WSK 應用程式的需求決定了應用程式應該使用哪一種方式。整個 WSK 文檔裡提供了如何使用這兩種方法的例子。下面列出總結了每一種方法的一些要點。
Using Winsock Kernel Functions
- WSK應用程式驅動socket操作,這意味著WSK應用程式控制何時會有socket操作的發生。透過WSK應用程式來簡化同步的需求。
- WSK應用程式提供IRPs給socket函式。這些IRPs會在WSK子系統內形成佇列,直到socket操作完成以後。更多有關IRPs與WSK函式的訊息查閱Using IRPs with Winsock Kernel Functions。
- WSK應用程式可以使用blocking socket操作,等待WSK子系統完成每一個IRP操作。
- 為了能夠在連線導向socket上確保數據傳輸的高效性,WSK應用程式可能需要在某些情境下保留多個socket操作佇列,以防止在datagram sockets上傳入數據包被丟棄或是防止在listening sockets上傳入連線被丟棄。
- WSK應用程式對於數據傳輸提供了數據緩衝區。這減少了數據需要複製的次數。然而,如果一個WSK應用程式保留了多個數據傳輸操作佇列,則應用程式必須對於每一個數據操作佇列提供給WSK子系統相對的數據緩衝區。因此,WSK應用程式可能需要額外的記憶體資源。
Using Event Callback Functions
- WSK子系統驅動socket操作,這意味著WSK子系統透過 socket 的事件回呼函式來通知WSK應用程式。WSK應用程式可能需要更複雜的同步機制去處理事件回呼函式的異步特性。
- WSK應用程式不會使用IRPs來進行socket操作。
- WSK應用程式不需要對socket操作生成佇列。當socket事件發生時,WSK子系統會盡速的調用WSK應用程式的事件回呼函式。如果WSK 應用程式可以保持跟上事件回呼函式被調用的速率,則使用事件回呼函式可以提供更高的效率以及減少數據丟包或是傳入連線丟包的機會。
- WSK子系統對於數據傳輸操作提供數據緩衝區。WSK應用程式必須在合理的時限內或是立即的釋放這些數據緩衝區,才能夠讓WSK子系統不會耗盡系統的記憶體資源。因此,WSK可能需要複製數據從 WSK子系統的緩衝區到它自己內部的數據緩衝區。
Note 以上列出來的未必詳盡。在一些特定的WSK應用程式上要選擇最佳的方式可能需要考慮其他可能的關鍵點。
Winsock Kernel Dispatch Tables
Winsock Kernel(WSK)的socket object包含了指向提供調度表(provider dispatch table)結構的指標,調度表中包含了指向socket函式的指標。WSK應用程式呼叫了調度表內的函式來執行網路I/O操作。因為每一個WSK socket category支持不同的socket函式集合,所以在WSK Network
Programming Interface (NPI)對於每一個WSK socket類別定義了不同的提供者調度表(provider dispatch table)結構。
如果WSK應用程式要在它建立的socket使用事件回呼函式,則它必須提供客戶調度表(client dispatch table)結構,客戶調度表包含函式指標指向socket的事件回呼函式。由於每一個WSK socket支援不同的事件回呼函式集合,所以WSK NPI對於每一種WSK socket定義了不同的客戶調度表(client dispatch table)集合。
Note Basic sockets 不支援任何的事件回呼函式。因此,basic socket沒有定義任何的client dispatch table。
Winsock Kernel Extension Interfaces
Winsock核心(WSK) Network Programming Interface (NPI)支援擴展接口。WSK子系統可以使用擴展接口在現有WSK NPI所定義的socket函式或事件回呼函式以外,另外擴充WSK socket的功能。每一個擴展接口通過NPI定義並且獨立於WSK NPI。現在的階段並沒有定義擴展接口。WSK應用程式可以透過SIO_WSK_REGISTER_EXTENSION IOCTL操作登記成為WSK子系統所支援的擴展接口。更多有關註冊擴展接口請看 Registering an Extension Interface。
Using IRPs with Winsock Kernel Functions
Winsock Kernel (WSK) Network
Programming Interface (NPI)對於網路I/O操作的異步完成使用了IRPs。每一個WSK函式提取IRP的指標作為參數。當WSK完成函式操作以後,WSK子系統會完成這個IRP。
一個WSK應用程式用來傳遞給WSK函式的IRP可以透過以下任何一種方式發起。
- WSK應用程式調用IoAllocateIrp函式來配置IRP。在這種情形下,WSK應用程式最少必須配置一個I/O stack location給IRP。
- WSK應用程式重新使用一個已完成的IRP(先前已配置)。在這種情形下,WSK必須調用IoReuseIrp來重新初始化這個IRP。
- WSK應用程式使用的IRP,這個IRP可能是由它更高層的驅動或是由I/O manager所傳遞給它的。在這種情形下,IRP最少需要一個可用的I/O stack location給WSK子系統使用。
- WSK應用程式調用IoAllocateIrp函式來配置IRP。在這種情形下,WSK應用程式最少必須配置一個I/O stack location給IRP。
- WSK應用程式重新使用一個已完成的IRP(先前已配置)。在這種情形下,WSK必須調用IoReuseIrp來重新初始化這個IRP。
- WSK應用程式使用的IRP,這個IRP可能是由它更高層的驅動或是由I/O manager所傳遞給它的。在這種情形下,IRP最少需要一個可用的I/O stack location給WSK子系統使用。
在WSK應用程式擁有一個IRP可以用來調用WSK函式以後,它可以為這個IRP設定IoCompletion常式,當WSK子系統完成這個IRP操作以後就可以調用這個常式。WSK應用程式可以調用IoSetCompletionRoutine函式來設定IoCompletion常式。依據如上三種IRP發起的方式,可以選擇要不要使用IoCompletion常式。
- 如果由WSK應用程式配置IRP,或是重新使用先前已經配置的IRP,則它在調用 WSK 函式以前必須對 IRP 設定一個 IoCompletion 常式。在這種情形底下,WSK 應用程式為了確保常式總是能夠被 WSK 子系統所調用,所以WSK應用程式必須在IoSetCompletionRoutine內設定InvokeOnSuccess, InvokeOnError, 以及InvokeOnCancel這些參數為TRUE。此外,為了設定這個IRP,IoCompletion常式總是回傳STATUS_MORE_PROCESSING_REQUIRED來重新取得IRP的操控權。在調用IoCompletion常式時,如果WSK應用程式完成了IRP的使用,則它在IoCompletion回傳結果給系統之前應該調用IoFreeIrp。如果WSK應用程式不釋放IRP則它可以重新使用這個IRP來調用其他的WSK函式。
- 如果WSK應用程式使用來自於上層驅動或是I/O manager的IRP,則在WSK函式完成後如果有必要通知WSK應用程式操作已經完成,則此情況下它應該要為IRP設定IoCompletion常式。如果WSK應用程式沒有設定IoCompletion常式,則當IRP完成時會按照正常的完成處理回傳給上層驅動或是I/O manager。如果WSK應用程式為IRP設定IoCompletion 常式,則IoCompletion常式可以回傳STATUS_SUCCESS或是STATUS_MORE_PROCESSING_REQUIRED。如果回傳STATUS_SUCCESS,則將正常處理IRP完成的動作。如果回傳STATUS_MORE_PROCESSING_REQUIRED,則WSK應用程式必須在WSK函式完成操作以後,自己調用IoCompleteRequest來完成IRP。WSK應用程式絕不應該釋放來自於上層驅動或是I/O manager的IRP。
Note 如果WSK應用程式對於來自於高層的驅動或是IO管理員的IRP有設定IoCompletion 常式, 則在IoCompletion裡需要檢查PendingReturned 是否為真,如果為真則需要呼叫IoMarkIrpPending 。更多訊息請參考 Implementing an
IoCompletion Routine.
Note 如果WSK應用程式對於來自於高層的驅動或是IO管理員的IRP有設定IoCompletion 常式, 則在IoCompletion裡需要檢查PendingReturned 是否為真,如果為真則需要呼叫IoMarkIrpPending 。更多訊息請參考 Implementing an
IoCompletion Routine.
沒有留言:
張貼留言