【文章內(nèi)容簡(jiǎn)介】
使用數(shù)據(jù)報(bào)式套接字。 原始式套接字( SOCK_RAW) : 該接口允許對(duì)較低層協(xié)議,如 IP、 ICMP 直接訪問(wèn)。常用于檢驗(yàn)新的協(xié)議實(shí)現(xiàn)或訪問(wèn)現(xiàn)有服務(wù)中配置的新設(shè)備。 SOCKET 基本概念 有了以上的了解 ,我們下面來(lái)介紹 SOCKET。 在一個(gè)網(wǎng)絡(luò)通信中,不同主機(jī)上的兩個(gè)進(jìn)程交換數(shù)據(jù)。我們就將網(wǎng)絡(luò)通信的每端稱(chēng)為端點(diǎn)。 SOCKET 就是一個(gè)網(wǎng)絡(luò)端點(diǎn)的抽象。為了進(jìn)行網(wǎng)絡(luò)通信(通過(guò) SOCKET 接口),程序在網(wǎng)絡(luò)對(duì)話的每端都需要一Q260046902 專(zhuān)業(yè)做論文 XIII 個(gè) SOCKET。兩個(gè) SOCKET 之間的連接可以是面向連接的或面向無(wú)連接的。 SOCKET 模型采用“打開(kāi)-讀-寫(xiě)-關(guān)閉”方式。 在建立 SOCKET 時(shí)不用指明一個(gè)地址,在 調(diào)用 SOCKET 函數(shù)時(shí),將返回一個(gè)指向描述符入口的 SOCKET 句柄。作為程序員,訪問(wèn)描述符表的唯一途徑就是通過(guò) SOCKET描述符。建立一個(gè) SOCKET,意味著數(shù)據(jù)結(jié)構(gòu)分配存儲(chǔ)空間。 圖 顯示一個(gè)簡(jiǎn)化的SOCKET 數(shù)據(jù)結(jié)構(gòu)。 P o i n t e r t o s t r u c t u r eP r o t o c o l F a m i l yT y p e o f S e r v i c eL o c a l I P A d d r e s sR e m o t e I P A d d r e s sL o c a l P r o t o c o l P o r tR e m o t e P r o t o c o l P o r t協(xié) 議 簇服 務(wù) 類(lèi) 型本 地 I P 地 址遠(yuǎn) 地 I P 地 址索 引 描 述 符 表 S O C K E T 數(shù) 據(jù) 結(jié) 構(gòu) 圖 socket 結(jié)構(gòu)圖 我們知道, INTERNET 上的每臺(tái)主機(jī)都有一個(gè)唯一的互聯(lián)網(wǎng)地址,每臺(tái)主機(jī)內(nèi)特定的應(yīng)用程序(或進(jìn)程)都使用協(xié)議端口作為它的地址。 INTERNET 程序必須使用TCP/IP 協(xié)議在 INTERNET 上傳輸數(shù)據(jù)。總之,兩個(gè)網(wǎng)絡(luò)程序之間的一個(gè)網(wǎng)絡(luò)連接包括下面五種信息: ? 本地協(xié)議端口,指出接收數(shù)據(jù)包的進(jìn)程 ? 本地主機(jī)地址,指出接收數(shù)據(jù)包的主機(jī) ? 遠(yuǎn)地協(xié)議端口,指出目的進(jìn)程或程序 ? 遠(yuǎn)地 主機(jī)地址,指出目的主機(jī) ? 協(xié)議,指出程序在網(wǎng)絡(luò)上傳輸數(shù)據(jù)時(shí)使用的協(xié)議 建立 SOCKET 當(dāng)編寫(xiě) TCP/IP 程序時(shí), SOCKET 接口可以讓你的程序通過(guò)一個(gè) SOCKET 連接使用UDP 或 TCP 來(lái)建立 SOCKET 和將 SOCKET 連到目的主機(jī)上。為了建立 SOCKET,程序可以調(diào)用 SOCKET 函數(shù)。 SOCKET 函數(shù)返回一個(gè) SOCKET 句柄。該句柄確定一個(gè)提供此 SOCKET信息的描述符表入口。下面程序顯示了 SOCKET 函數(shù)調(diào)用的例子。 Socket_handle=socket(protocol_family,socket_type,protocol)。 當(dāng)建立 SOCKET 時(shí),三個(gè)參數(shù)必須賦值:協(xié)議簇, SOCKET 類(lèi)型,協(xié)議。 協(xié)議簇:確定一些相關(guān)的協(xié)議,比如 TCP/IP 協(xié)議組,用符號(hào) PF_INET 表示。 PF_VNIX 表示 VNIX 內(nèi)部協(xié)議簇, PF_NS 表 ,美目, 示網(wǎng)絡(luò)服務(wù)協(xié)議簇。 Q260046902 專(zhuān)業(yè)做論文 XIV SOCKET 類(lèi)型:參數(shù)指明程序?qū)?SOCKET 用于數(shù)據(jù)報(bào)傳輸還是字節(jié)流傳輸。我們知道 TCP/IP 可以讓程序使用面向連接或無(wú)連接的網(wǎng)絡(luò)通信。在面向連接的通信,數(shù)據(jù)按字節(jié)流傳送;在面向無(wú)連接的通信時(shí),數(shù)據(jù)是按照數(shù)據(jù)報(bào)傳送。 SOCKET 接口使用符號(hào) SOCK_DGRAM 表示數(shù)據(jù)報(bào),用 SOCK_STREAM 表示字節(jié)流。 協(xié)議參數(shù):指出程序希望使用的具體協(xié)議。 我們知道, TCP/IP 協(xié)議包括IP,ICMP,TCP,UDP 等幾個(gè)協(xié)議。該參數(shù)就是讓你指明 SOCKET 請(qǐng)求使用的協(xié)議。 TCP 協(xié)議使用 IPPROTO_TCP,符號(hào) IPPROTO_UDP 表示 UDP 協(xié)議。 配置 SOCKET 在使用 SOCKET 進(jìn)行網(wǎng)絡(luò)通信以前,必須配置此 SOCKET。更為重要的是, SOCKET的內(nèi)部必須包含正確的地址。 SOCKET 結(jié)構(gòu)必須包括本地主機(jī)及遠(yuǎn)地主機(jī) 正確的協(xié)議端口和 IP 地址。當(dāng)用 SOCKET 函數(shù)建立 SOCKET 時(shí),不用指明協(xié)議端口或主機(jī)地址。你可以根據(jù)程序 打算怎樣使用此 SOCKET,調(diào)用不同的 API函數(shù)來(lái)進(jìn)行配置。 表 例出了配置 SOCKET API 函數(shù)。 S O K C E T 用 途 本 地 信 息 遠(yuǎn) 地 信 息面 向 連 接 客 戶(hù) c o n n e c t 保 存 本 地 信 息 c o n n c e t 保 存 遠(yuǎn) 地 信 息面 向 連 接 的 服 務(wù) 器 b i n d L i s t e n 和 a c c e p t無(wú) 連 接 客 戶(hù) b i n d s e n d t o無(wú) 連 接 服 務(wù) 器 b i n d r e c v f r o m 表 由于我們使用的采用面向無(wú)連接的 UDP 協(xié)議,所以我們著重介紹面向無(wú)連接的通信來(lái)配置 SOCKET。 面向無(wú)連接 通信 的建 立 在前面的系統(tǒng)概述中,我們已經(jīng)說(shuō)明了該系統(tǒng)選擇了面向無(wú)連接服務(wù)協(xié)議 UDP。那么利用 SOCKET 如何來(lái)建立無(wú)連接的通信呢?下面將進(jìn)行詳細(xì)的解釋。 首先我們了看一下客戶(hù)端和服務(wù)器端建立面向無(wú)連接的通信過(guò)程。 如圖 。 Q260046902 專(zhuān)業(yè)做論文 XV C o n n e c t i o n l e s s S e r v e rS o c k e t ( )B i n d ( )R e c v f r o m ( )S e n d t o ( )阻 塞 直 到 從 客 戶(hù) 接 收 到 數(shù) 據(jù) 為 止S e r v e r服 務(wù) 器R e c v f r o m ( )S e n d t o ( )B i n d ( )S o c k e t ( )C o n n e c t i o n l e s s C l i e n tC l i e n t客 戶(hù)無(wú) 連 接 的 服 務(wù) 器無(wú) 連 接 的 客 戶(hù)數(shù) 據(jù) 請(qǐng) 求 數(shù) 據(jù) 應(yīng) 答 圖 通信過(guò)程圖 使用面向無(wú)連接的通信,由于無(wú)連接的客戶(hù)端程序沒(méi)有和遠(yuǎn)的主機(jī)建立直接連接,所以它必須對(duì)協(xié)議端口進(jìn)行偵聽(tīng),以便接 收以及對(duì)它服務(wù)請(qǐng)求產(chǎn)生的數(shù)據(jù)報(bào)應(yīng)答。SOCKET API 中的 bind 函數(shù)讓程序?qū)⒁粋€(gè)本地地址(包括主機(jī)地址和協(xié)議端口 ) 和一個(gè) SOCKET 聯(lián)系起來(lái)。 建立服務(wù)器程序時(shí),應(yīng)該將服務(wù)器程序設(shè)計(jì)成等待客戶(hù)的請(qǐng)求。我們知道, TCP/IP傳輸層通過(guò)協(xié)議端口及應(yīng)用程序通信。即為了接收客戶(hù)請(qǐng)求,服務(wù)器程序必須對(duì)傳輸層的一個(gè)特定的協(xié)議端口進(jìn)行偵聽(tīng)。當(dāng)服務(wù)器程序使用 SOCKET 接口時(shí),它使用 bind函數(shù)讓 SOCKET 執(zhí)行體登記一個(gè)協(xié)議端口。也就是說(shuō),程序公司 SOCKET 執(zhí)行體使用哪一個(gè)協(xié)議端口進(jìn)行數(shù)據(jù)傳送。 SOKCET 執(zhí)行提接 著告訴傳輸層某個(gè)特定 的端口以被使用,并將其收到的所有數(shù)據(jù)傳送給 socket API。 下面的程序顯示了 bind 函數(shù)的調(diào)用。 Bind(sock,(LPSOCKADDR)amp。sockin,sizeof(sockin)))。 該函數(shù)的第一個(gè)參數(shù)是指向剛才建立的 socket,第二個(gè)參數(shù)是一個(gè)指向包含有本機(jī) IP 地址和端口信息的 sockaddr_in 結(jié)構(gòu)類(lèi)型的指針,其描述如下: Q260046902 專(zhuān)業(yè)做論文 XVI =AF_INET。 =。 =htons(USERPORT)。 bind(sock,(LPSOCKADDR)amp。sockin,sizeof(sockin)))。 第一個(gè)參數(shù)指定地址簇,在 WINDOWS 下僅支持 AF_INET(TCP/IP);第二,第三個(gè)參數(shù)指明本地主機(jī)地址及端口號(hào),經(jīng)過(guò) bind()將進(jìn)程在網(wǎng)絡(luò)上標(biāo)識(shí)出來(lái)。由于 1024以?xún)?nèi)的號(hào)都是保留的,因此如無(wú)特許需要一般不能將 的端口號(hào)設(shè)置為 1024 以?xún)?nèi)的值。即 USERPORT 要大于 1024。 端口綁定以后,如何通過(guò)一個(gè) 無(wú)連接的 SOCKET發(fā)送數(shù)據(jù),可以使用 sendto 和sendmsg 這兩個(gè) socket API 函數(shù)。 Result=sendto(socket_handle,message_buffer,buffer_length, special_falgs,socket_address_structure,address_structure_length); 它的第一個(gè)參數(shù)是許多 API 函數(shù)要求的 SOCKET 句柄。 SOCKET 句柄指明一個(gè)描述符入口,描述符入口指向一個(gè)內(nèi)部 SOCKET 數(shù)據(jù)結(jié)構(gòu)。第二個(gè)參數(shù)指向一個(gè)包含傳輸信息的數(shù)據(jù)緩沖區(qū)。你必 須為這個(gè)緩沖區(qū)分配內(nèi)存,并將你的數(shù)據(jù)填放到此緩沖區(qū)內(nèi)。第三個(gè)參數(shù)簡(jiǎn)單地指明傳送數(shù)據(jù)緩沖區(qū)的大小。 第四個(gè)參數(shù)是可選標(biāo)志,可以對(duì)傳輸進(jìn)行控制。第五 個(gè)參數(shù)是指明目的地址,第六個(gè)參數(shù)指明目的地址的大小。 Sendto 函數(shù)相對(duì)應(yīng)的是 recvfrom。下面是一個(gè)典型的 recvfrom 函數(shù)的調(diào)用: Result=recvfrom(socket_handle,message_buffer,buffer_length,special_flags,socket_address_structure,address_structure_length); 它可以從本地協(xié)議端口獲得數(shù)據(jù),并將數(shù)據(jù)保存在報(bào)文數(shù)據(jù)緩沖區(qū) (函數(shù)的第二個(gè)參數(shù) )中。也可以從數(shù)據(jù)報(bào)頭分離出發(fā)送數(shù)據(jù)報(bào)的主機(jī)的網(wǎng)絡(luò)地址。 使用 recvfrom 函數(shù)地服務(wù)器程序總要分離出發(fā)送者的地址。也就是說(shuō),服務(wù)器程序需要知道誰(shuí)發(fā)送請(qǐng)求信息。當(dāng)客戶(hù)端程序使用 recvfrom 函數(shù)時(shí),如果客戶(hù)想繼續(xù)進(jìn)行網(wǎng)路對(duì)話的話,可能需要分離出發(fā)送者的地址。另外,客戶(hù)端也可能需要分離出發(fā)送者的地址已證明數(shù)據(jù)來(lái)自希望的主機(jī)。 也就是說(shuō), recvfrom 函數(shù)從數(shù)據(jù)報(bào)頭將發(fā)送數(shù)據(jù)報(bào)的主機(jī)網(wǎng)絡(luò)地址拷貝到recvfrom 第五個(gè)參數(shù)指向的 socket 地址結(jié)構(gòu)中。 如果 socket 結(jié)構(gòu)地址域包含一個(gè)有效的指針, recvfrom 函數(shù)將分離出發(fā)送者的地址。如果 socket 地址結(jié)構(gòu)域是NULL,recvfrom 函數(shù)不從數(shù)據(jù)報(bào)頭拷貝或 抽取發(fā)送者的地址。 Q260046902 專(zhuān)業(yè)做論文 XVII 正是通過(guò) sendto()和 recvfrom()過(guò)程的交互來(lái)完成整個(gè)通信過(guò)程。當(dāng)任何一方想中止通信時(shí) ,只要調(diào)用 closesocket()就可以了。另外,與程序啟動(dòng)時(shí)調(diào)用的WSAStartup()函數(shù)相對(duì)應(yīng),程序結(jié)束前,需要調(diào)用 WSACleanup()來(lái)通知 Winsock Stack釋放 Socket 所占用的資源。 HOOK 編程 WINDOWS 操作系統(tǒng)是基于消息處理的 系統(tǒng),系統(tǒng)內(nèi)部及系統(tǒng)與應(yīng)用程序之間都是通過(guò)消息傳遞消息的,在 WNDOWS 操作系統(tǒng)下,使用鉤子( HOOK)截獲并處理系統(tǒng)范圍內(nèi)的消息 ,才能完成普通程序無(wú)法完成的功能。 勾子 (Hook),是 Windows 消息處理機(jī)制的一個(gè)平臺(tái) ,應(yīng)用程序可以在上面設(shè)置子程以監(jiān)視指定窗口的某種消息,而且所監(jiān)視的窗口可以是其他進(jìn)程所創(chuàng)建的。當(dāng)消息到達(dá)后,在目標(biāo)窗口處理函數(shù)之前處理它。勾子機(jī)制允許應(yīng)用程序截獲處理 window消息或特定事件 。 勾子實(shí)際上是一個(gè)處理消息的程序段,通過(guò)系統(tǒng)調(diào)用,把它掛入系統(tǒng)。每當(dāng)特定的消息發(fā)出,在沒(méi)有到達(dá)目的窗口前,勾子程序就先捕獲該消息,亦即勾子函數(shù)先得到控制權(quán)。 下圖說(shuō)明了鉤子在消息處理鏈中的位置和作用。在安裝鉤子程序之前,系統(tǒng)直接處理應(yīng)用程序的消息,此時(shí)消息傳遞路徑如圖虛線所示;而安裝勾子后,每當(dāng)特定的消息發(fā)出,在沒(méi)有到達(dá)目的窗口前,勾子程序就先捕獲此消息,其內(nèi)置的勾子函數(shù)就可以對(duì)消息進(jìn)行處理,可以改變消息后才向系統(tǒng)傳遞,也可以不修改繼續(xù)傳遞,還可以丟棄此消息,從而中止消息的傳遞,這是消息的傳遞路徑如圖 。 圖 勾子消息處理圖 勾子的種類(lèi)很多其作用也不同,如鍵盤(pán)勾子獲得鍵盤(pán)消息,鼠標(biāo)勾子可以截獲鼠標(biāo)消息,外殼谷子可以截獲啟動(dòng)或關(guān)閉程序的消息,日志勾子可以監(jiān)視及記錄輸入事件。勾子分為專(zhuān)用勾子和全局勾子,線程專(zhuān)用勾子只監(jiān)視制定的線程,要監(jiān)視系統(tǒng)中Windows 系統(tǒng) 應(yīng)用程序 勾子程序 Q260046902 專(zhuān)業(yè)做論文 XVIII 所有的線程,必須用到全局勾子。對(duì)于可監(jiān)控系統(tǒng)范圍消