多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國(guó)內(nèi)最全I(xiàn)T社區(qū)平臺(tái) 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁(yè) > 互聯(lián)網(wǎng) > TCP/IP 在 Windows 下的實(shí)現(xiàn)

TCP/IP 在 Windows 下的實(shí)現(xiàn)

來(lái)源:程序員人生   發(fā)布時(shí)間:2014-09-15 03:07:05 閱讀次數(shù):3019次

        Windows 實(shí)現(xiàn)TCP/IP 協(xié)議也是建立在上一篇博客的OSI 基礎(chǔ)之上的。用戶態(tài)是由ws2_32.dll 和一些其它服務(wù)提供者的 dll 共同實(shí)現(xiàn),其中ws2_32.dll 是一個(gè)框架,可以容納很多的服務(wù)提供者,這些服務(wù)提供者其實(shí)就是各種協(xié)議的實(shí)現(xiàn)者,如比較常見的有 TCP/IP 協(xié)議,IPX 協(xié)議。而 TCP/IP 協(xié)議的服務(wù)實(shí)現(xiàn)是由 msafd.dll 和 mswsock.dll 來(lái)完成。HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesWinSock2,該注冊(cè)表下記錄了協(xié)議(服務(wù))及其一些其它的信息。

        就 TCP/IP 而言,我們普遍會(huì)使用 posix標(biāo)準(zhǔn)的 socket 接口來(lái)完成我們應(yīng)用程序的功能,這樣要想完成跨平臺(tái)的代碼就會(huì)比較方便。

        在上一篇文章中,我們知道,tcp/ip 協(xié)議的用戶態(tài)部分由msafd.dll 完成,它與內(nèi)核部分的 afd.sys 交互來(lái)實(shí)現(xiàn) socket 接口的系統(tǒng)調(diào)用。然后 afd.sys 完成 socket 的一些機(jī)制,并且和 tcpip.sys 驅(qū)動(dòng)程序交互,總結(jié)一下如下。

        1.      Msafd.dll : socket 接口的用戶態(tài)部分,與afd.sys 通信。

        2.      Afd.sys  : socket 接口的內(nèi)核態(tài)部分,滿足 msafd.dll的調(diào)用,向下與 tcpip.sys 通信。

        3.      Tcpip.sys : tcp/ip 協(xié)議的主要實(shí)現(xiàn)部分,滿足afd.sys 的調(diào)用,向下與小端口網(wǎng)卡驅(qū)動(dòng)通過(guò) IRP通信。

        4.      socket 的概念是在 msafd.dll和 afd.sys 中才有的,它們兩個(gè)實(shí)現(xiàn)了 socket 的用戶態(tài)和內(nèi)核態(tài)部分。它們的下層是傳輸層(TDI)層,TDI 層完成了 TCP, UDP, RawIp的機(jī)制,在 TDI 層中,只有地址對(duì)象,連接對(duì)象,控制通道的概念。TDI 的下層是網(wǎng)絡(luò)層(IP 層),在 IP 層中,只有 Packet 的概念,收到數(shù)據(jù)時(shí),通過(guò) IP 包中的標(biāo)識(shí),知道要提交給 TCP 或 UDP 等處理。TDI 層和 IP 層都由 tcpip.sys 來(lái)實(shí)現(xiàn)。

        知道上面的概念后,就有了比較清晰的結(jié)構(gòu),當(dāng)然驅(qū)動(dòng)和設(shè)備的管理由 IO 管理器來(lái)管理,但tcpip 協(xié)議族卻沒(méi)有用常規(guī)設(shè)備棧的方式來(lái)處理數(shù)據(jù)包,afd.sys 與 tcpip.sys 以及 tcpip.sys 與 miniport 驅(qū)動(dòng)之間都是由發(fā)送 IRP 來(lái)實(shí)現(xiàn)。這也使中間過(guò)濾層驅(qū)動(dòng)的實(shí)現(xiàn)略微復(fù)雜,這里且不談。

那么我們把上面零散的概念串起來(lái),看看從普通的 socket 接口到數(shù)據(jù)最終由網(wǎng)卡發(fā)出的整個(gè)過(guò)程。

        Socket :

        Ws2_32.dll 加載時(shí)會(huì)根據(jù)注冊(cè)表初始化服務(wù)提供者,服務(wù)者會(huì)告知自己支持的地址族,socket 類型,和協(xié)議類型。當(dāng)我們調(diào)用socket(AF_INET, SOCK_DGRAM, IPPROT_UDP) 來(lái)創(chuàng)建一個(gè) UDP 類型的套接字的時(shí)候,根據(jù)傳入的參數(shù),會(huì)定位到 msafd.dll 這個(gè)服務(wù)提供者,并會(huì)調(diào)用相應(yīng)的 socket 創(chuàng)建接口,它會(huì)打開設(shè)備 DeviceAfdEndPoint ,由于 afd.sys 創(chuàng)建了一個(gè) DeviceAfd 設(shè)備,所以一個(gè) IRP_MJ_CREATE 的 IRP 便會(huì)發(fā)送到 afd.sys 驅(qū)動(dòng)的創(chuàng)建函數(shù),它會(huì)創(chuàng)建一個(gè)FAD_FCB 結(jié)構(gòu)體來(lái)表示這個(gè)套接字,并且記錄下 FileObject,并返回。

        Bind :

        要想接收數(shù)據(jù)包,我們會(huì)把 socket 綁定到本地的一個(gè)IP-Port 對(duì),就是調(diào)用 Bind 接口,msafd.dll 會(huì)通過(guò)一個(gè)控制消息,次功能號(hào)為 IOCTL_AFD_BIND,此時(shí)afd.sys 會(huì)接著根據(jù)上面 FCB 記錄的設(shè)備名打開相應(yīng)的 DeviceUDP 設(shè)備,并把輸入?yún)?shù)標(biāo)識(shí)為是一個(gè)傳輸層的地址,那么 tcpip.sys 會(huì)創(chuàng)建接口就會(huì)創(chuàng)建一個(gè)地址對(duì)象來(lái)表示這次綁定,當(dāng)然還會(huì)分配相應(yīng)的端口信息。

        Connect:

        如果是 TCP,還需要連接到對(duì)方的socket,與 Bind 類似,它也會(huì)根據(jù) FCB 記錄的設(shè)備名打開相應(yīng)的設(shè)備,并把輸入?yún)?shù)標(biāo)識(shí)為是一個(gè)連接對(duì)象,tcpip.sys 會(huì)創(chuàng)建一個(gè)連接對(duì)象來(lái)表示這次連接。

        其實(shí)在 TDI 層,還有一種叫做控制通道,當(dāng)其它驅(qū)動(dòng)想得到 TDI 層的一些信息,如當(dāng)前的 TCP或 UDP 連接有哪些,那么它會(huì)直接打開 DeviceTCP 等設(shè)備,由于沒(méi)有傳入?yún)?shù),那么 tcpip.sys 則會(huì)創(chuàng)建一個(gè)控制通道。TDI 層這些對(duì)象的標(biāo)識(shí)都會(huì)保存在與之對(duì)應(yīng)的 FileObject->FsContext2 里,以便后來(lái)區(qū)分。

        當(dāng)前面準(zhǔn)備工作做好后,我們就來(lái)看數(shù)據(jù)的接收和發(fā)送。

        SendTo:

        由 msafd.dll 發(fā)送一個(gè) IOCTL_AFD_SEND_DATAGRAM到 afd.sys ,afd.sys 創(chuàng)建一個(gè)主功能號(hào)為 IRP_MJ_INTERNAL_DEVICE_CONTROL ,次功能號(hào)為 TDI_SEND_DATAGRAM的 IRP 到 tcpip.sys,tcpip.sys 調(diào)用相就的 UDPSendDatagram,組裝一個(gè) UDP 包,最后通過(guò) IpSendDatagram 到協(xié)議層,然后由相應(yīng)的小端口驅(qū)動(dòng)發(fā)送出去。

        RecvFrom:

        接收數(shù)據(jù)稍微復(fù)雜一點(diǎn),接收數(shù)據(jù)都是由afd.sys 驅(qū)動(dòng)發(fā)送一個(gè)次功能號(hào)為 TDI_RECEIVE_DATAGRAM (afd.sys 與 tcpip.sys 的傳輸層都是以 IRP_MJ_INTERNAL_DEVICE_CONTROL 為主功能號(hào))的 IRP 到 TDI 層,而 TDI 層都是以接收請(qǐng)求的形式來(lái)掛在地址對(duì)象的接收請(qǐng)求(DATAGRAM_RECEIVE_REQUEST)隊(duì)列中,在地址對(duì)象創(chuàng)建的時(shí)候會(huì)創(chuàng)建這個(gè)隊(duì)列。那么什么時(shí)候這個(gè)請(qǐng)求會(huì)被滿足呢,這要從網(wǎng)卡接到數(shù)據(jù)說(shuō)起。當(dāng)網(wǎng)卡接收到數(shù)據(jù)時(shí),協(xié)議驅(qū)動(dòng)也會(huì)收到這個(gè)數(shù)據(jù),一般情況下只有能處理這個(gè)協(xié)議的驅(qū)動(dòng)才會(huì)去處理這個(gè)包,此時(shí)就會(huì)進(jìn)行到 tcpip.sys 的協(xié)議部分,即 IP 協(xié)議,tcpip.sys 根據(jù)相應(yīng)的標(biāo)識(shí),確定是 IP 包,因?yàn)?tcpip.sys 還完成了 ARP 包的處理,最后會(huì)上交到 Ipv4 的處理流程,它會(huì)調(diào)用ProcessFragment ->IpDispatchProtocol ,IpDispatchProtocl 會(huì)區(qū)分出是什么包,如果是 UDP 包,由會(huì)調(diào)用UDPReceive ,并進(jìn)一步根據(jù)地址對(duì)象鏈表來(lái)找到匹配的地址對(duì)象,DGDeliverData 來(lái)交付數(shù)據(jù),它會(huì)查看對(duì)址對(duì)象的接收請(qǐng)求隊(duì)列中是否有請(qǐng)求,如果沒(méi)有,則查看是否注冊(cè)了接收數(shù)據(jù)的處理過(guò)程,如果也沒(méi)有注冊(cè),那么就會(huì)丟掉這個(gè)包,這就是 UDP 不可靠的一個(gè)原因。

        那么有人就會(huì)有疑問(wèn),我們?nèi)绻{(diào)用完 Bind 之后,還沒(méi)來(lái)得及調(diào)用 RecvFrom ,那么,接收到的包不就丟了么,其實(shí),在調(diào)用 Bind 之后,就會(huì)馬上發(fā)送一個(gè)接收請(qǐng)求到隊(duì)列中,也就避免了這種情況的發(fā)生。這只是整個(gè)過(guò)程的導(dǎo)火索,在 Bind 里面它是通過(guò)調(diào)用TdiReceiveDatagram 來(lái)投遞一個(gè)接收請(qǐng)求的,它會(huì)創(chuàng)建一個(gè)TDI_RECEIVE_DATAGRAM 的 IRP,并為這個(gè) IRP 設(shè)置一個(gè)完成例程PacketSocketRecvComplete, tcpip.sys 會(huì)響應(yīng)這個(gè) IRP,并在相應(yīng)的地址對(duì)象的接收請(qǐng)求隊(duì)列中插入一個(gè)請(qǐng)求,并設(shè)置這個(gè)請(qǐng)求的完成函數(shù)為DGReceiveComplete,用戶完成函數(shù)為DispDataRequestComplete。 當(dāng)通過(guò) DGDeliverData 交付數(shù)據(jù)時(shí),如果隊(duì)列中有請(qǐng)求,那么就去滿足這個(gè)請(qǐng)求,拷貝數(shù)據(jù)到與這個(gè)請(qǐng)求相應(yīng)的緩沖中,當(dāng)調(diào)用請(qǐng)求的完成函數(shù) DGReceiveComplete,它會(huì)調(diào)用用戶完成函數(shù) DispDataRequestComplete,DiapDataRequestComplete會(huì)完成這個(gè) IRP,那么 IRP 的完成例程PacketSocketRecvComplete 就會(huì)得到調(diào)用了, 在 PacketSocketRecvComplete中(該函數(shù)在 afd.sys 中)要做的工作先暫停一下,回到 RecvFrom 的調(diào)用,在 RecvFrom 向下直到 afd.sys 層,它并不會(huì)直接發(fā)送 IRP 到 tcpip.sys 中去請(qǐng)求接收數(shù)據(jù),如果 FCB->DatagramList 中沒(méi)有數(shù)據(jù),它會(huì)把 msafd.dll 下發(fā)的這個(gè) IRP 放到 FCB->PendingIrpList 中,并掛起,所以到 tcpip.sys 的請(qǐng)求都是由在 Bind 最后發(fā)送的那個(gè)導(dǎo)火索引起,回到 PacketSocketRecvComplete 中,它會(huì)從FCB->PendingIrpList 中摘掉一個(gè) IRP 并插入一個(gè)數(shù)據(jù)包到 FCB->DatagramList 中,最后完成這個(gè) IRP,那么 RecvFrom 下發(fā)的這個(gè) IRP 就完成了。最后它又調(diào)用TdiReceiveDatagram 來(lái)投遞一個(gè)接收請(qǐng)求,然后周而復(fù)始。

        一個(gè) UDP Socket的大致過(guò)程就到此為止了。

生活不易,碼農(nóng)辛苦
如果您覺(jué)得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 国产亚洲视频在线播放大全 | 日韩久久网 | 91亚洲影院 | 精品国产福利在线观看一区 | 久久综合九色综合97欧美 | 激情综合五月天丁香婷婷 | 亚洲视频免费播放 | 最新中文字幕 | 波多野结衣在线一区二区 | 国产一区二区精品久久91 | 最新午夜宅男 | 国产三级精品三级在线专区1 | 久久久久久久久久久福利 | h视频免费 | 欧美区国产区 | 校园激情亚洲 | xxxwww日本高清 | 亚洲欧洲一区二区三区在线 | 久久精品这里有 | 天堂网在线网站成人午夜网站 | 欧美精品video | 美女视频一区二区三区 | 欧美一区二区三区四区视频 | 欧美18一19sex极品 | 国产亚洲久久 | 1000部精品久久久久久久久 | 美国毛片亚洲社区在线观看 | 伊人免费在线观看 | 免费jizz在线播放视频高清版 | 久久精品国产74国产 | 91色久| 亚洲精选 | 波多野结衣xxxx性精品 | 精品精品国产高清a毛片 | 亚洲人成影网站~色 | 国产精品视频国产永久视频 | 女性影院 | 欧美日韩天堂 | 亚洲欧美精品日韩欧美 | 日韩午夜网站 | 中文字幕一区二区三 |