1. 程式人生 > >關於Winsock:Winsock程式設計注意事項:與協議無關的帶外資料

關於Winsock:Winsock程式設計注意事項:與協議無關的帶外資料

流套接字抽象包括帶外(OOB)資料的概念。 許多協議允許以某種方式將輸入資料的部分標記為特殊,並且這些特殊資料塊可以按正常順序傳遞給使用者。 示例包括X.25和其他OSI協議中的加急資料,以及BSD UNIX使用TCP中的緊急資料。 以下部分以與協議無關的方式描述OOB資料處理。 使用TCP緊急資料實現的OOB資料的討論遵循與協議無關的解釋。 在每次討論中,recv的使用也意味著recvfrom,WSARecv和WSARecvFrom,對WSAAsyncSelect的引用也適用於WSAEventSelect。

協議獨立的OOB資料

OOB資料是與每對連線的流套接字相關聯的邏輯上獨立的傳輸通道。可以獨立於正常資料將OOB資料傳遞給使用者。 抽象定義OOB資料工具必須一次支援至少一個OOB資料塊的可靠傳遞。 該資料塊可以包含至少一個位元組的資料,並且至少一個OOB資料塊可以在任何時間等待遞送給使用者。 對於支援帶內信令的通訊協議(例如TCP,其中緊急資料按正常資料順序傳送),系統通常從正常資料流中提取OOB資料並單獨儲存(留下間隙) 普通資料流)。 這允許使用者在按順序接收OOB資料和不按順序接收OOB資料之間進行選擇,而不必緩衝所有中間資料。 可以檢視帶外(OOB)資料。

使用者可以使用帶有SIOCATMARK IOCTL的ioctlsocket或WSAIoctl函式來確定是否有任何OOB資料正在等待讀取。 對於正常資料流中OOB資料塊的位置概念有意義的協議,例如TCP,Windows套接字服務提供者維護一個概念標記,指示正常資料流中OOB資料的最後一個位元組的位置。 這對於支援SIOCATMARK的ioctlsocket或WSAIoctl函式的實現不是必需的。 是否需要存在或不存在OOB資料。

對於正常資料流中OOB資料塊的位置概念有意義的協議,應用程式可以內聯處理帶外資料,作為普通資料流的一部分。 這是通過使用setsockopt函式設定套接字選項SO_OOBINLINE來實現的。 對於其中OOB資料塊真正獨立於普通資料流的其他協議,嘗試設定SO_OOBINLINE會導致錯誤。 應用程式可以將ioctlsocket或WSAIoctl函式與SIOCATMARK IOCTL一起使用,以確定標記之前是否有任何未讀的OOB資料。 例如,它可以使用此資訊與其對等方重新同步,方法是確保在適當時丟棄資料流中標記之前的所有資料。

禁用SO_OOBINLINE(預設設定):

  • 如果應用程式使用WSAAsyncSelect註冊通知,則Windows套接字會通知應用程式FD_OOB事件,其方式與使用FD_READ完全相同,以通知正常資料的存在。 也就是說,當OOB資料到達而沒有先前排隊的OOB資料時,FD_OOB被髮布。 當使用MSG_OOB標誌讀取資料時也會發布FD_OOB,而某些OOB資料在讀取操作返回後仍保持排隊。 不會為OOB資料釋出FD_READ訊息。
  • 如果OOB資料在套接字上排隊,則Windows套接字將從select中返回,並使用相應的exceptfds套接字集。
  • 應用程式可以使用MSG_OOB呼叫recv來隨時讀取緊急資料塊。 OOB資料塊跳轉佇列。
  • 應用程式可以在沒有MSG_OOB的情況下呼叫recv來讀取普通資料流。 OOB資料塊不會出現在具有普通資料的資料流中。 如果在呼叫recv之後仍保留OOB資料,則Windows套接字在使用select時使用FD_OOB或exceptfds通知應用程式。
  • 對於OOB資料在普通資料流中具有位置的協議,單個recv操作不會跨越該位置。 一個recv返回標記之前的正常資料,並且需要第二個recv才能開始在標記之後讀取資料。

啟用SO_OOBINLINE後:

  • 不會為OOB資料釋出FD_OOB訊息。 出於select和WSAAsyncSelect函式的目的,OOB資料被視為正常,並通過在readfds中設定套接字或通過分別傳送FD_READ訊息來指示。
  • 應用程式無法呼叫recv,並將MSG_OOB標誌設定為讀取OOB資料塊。 返回錯誤程式碼WSAEINVAL。
  • 應用程式可以在沒有設定MSG_OOB標誌的情況下呼叫recv。 任何OOB資料都在正常資料流中以正確的順序傳遞。 OOB資料永遠不會與普通資料混合。 必須有三個讀取請求才能通過OOB資料。 第一個返回OOB資料塊之前的正常資料,第二個返回OOB資料,第三個返回OOB資料之後的正常資料。 換句話說,保留了OOB資料塊邊界。

當SO_OOBINLINE關閉時,WSAAsyncSelect例程特別適合處理帶外資料存在的通知。

TCP中的OOB資料

[!重要]
以下關於使用TCP緊急資料實現的帶外資料(OOB)的討論遵循伯克利軟體分發中使用的模型。 使用者和實施者應該意識到:

  • 目前,RFC 793存在兩種相互矛盾的解釋(其中引入了概念)。
  • Berkeley Software Distribution(BSD)中的OOB資料的實現不符合RFC 1122中指定的主機要求。

    具體地說,BSD中的TCP緊急指標指向緊急資料位元組之後的位元組,並且符合RFC的TCP緊急指標指向緊急資料位元組。 因此,        如果應用程式將緊急資料從相容BSD的實現傳送到與RFC 1122相容的實現,則接收器讀取錯誤的緊急資料位元組(它將位於數      據流中正確位元組之後的位元組讀取為緊急資料) 位元組)。

    為了最大限度地減少互操作性問題,建議應用程式編寫者不要使用OOB資料,除非需要與現有服務進行互操作。 敦促                  Windows套接字供應商記錄其產品實現的OOB語義(BSD或RFC 1122)。

具有URG(用於緊急)標誌集的TCP段的到達指示TCP資料流記憶體在單位元組的OOB資料。 OOB資料塊大小為一個位元組。 緊急指標是與TCP報頭中的當前序列號的正偏移,其指示OOB資料塊的位置(模糊地,如前所述)。 因此,它可能指向尚未收到的資料。

如果在包含緊急指標指向的位元組的TCP段到達時禁用SO_OOBINLINE(預設值),則從資料流中刪除OOB資料塊(一個位元組)並進行緩衝。 如果後續TCP段到達時設定了緊急標誌(和一個新的緊急指標),則當前排隊的OOB位元組可能會丟失,因為它被新的OOB資料塊替換(如Berkeley Software Distribution中所述)。 但是,它永遠不會在資料流中被替換。

啟用SO_OOBINLINE後,緊急資料將保留在資料流中。 因此,當新的TCP段到達包含緊急資料時,OOB資料塊永遠不會丟失。 現有的OOB資料標記將更新到新位置。

注意

設定SO_OOBINLINE套接字選項後,SIOCATMARK IOCTL始終返回TRUE,並將OOB資料作為普通資料返回給使用者。