6.5.5通信過(guò)程
主機(jī)A的應(yīng)用程序要能和主機(jī)B的應(yīng)用程序通信,必須通過(guò)Socket建立連接,而建立Socket連接必須需要底層TCP/IP協(xié)議來(lái)建立TCP連接。建立TCP連接需要底層IP協(xié)議來(lái)尋址網(wǎng)絡(luò)中的主機(jī)。我們知道網(wǎng)絡(luò)層使用的IP協(xié)議可以幫助我們根據(jù)IP地址來(lái)找到目標(biāo)主機(jī),但是一臺(tái)主機(jī)上可能運(yùn)行著多個(gè)應(yīng)用程序,如何才能與指定的應(yīng)用程序通信就要通過(guò)TCP或UPD的地址也就是端口號(hào)來(lái)指定。這樣就可以通過(guò)一個(gè)Socket實(shí)例唯一代表一個(gè)主機(jī)上的一個(gè)應(yīng)用程序的通信鏈路了。
當(dāng)客戶端要與服務(wù)端通信,客戶端首先要?jiǎng)?chuàng)建一個(gè)Socket實(shí)例,操作系統(tǒng)將為這個(gè)Socket實(shí)例分配一個(gè)沒(méi)有被使用的本地端口號(hào),并創(chuàng)建一個(gè)包含本地和遠(yuǎn)程地址和端口號(hào)的套接字?jǐn)?shù)據(jù)結(jié)構(gòu),這個(gè)數(shù)據(jù)結(jié)構(gòu)將一直保存在系統(tǒng)中直到這個(gè)連接關(guān)閉。在創(chuàng)建Socket實(shí)例的構(gòu)造函數(shù)正確返回之前,將要進(jìn)行TCP的三次握手協(xié)議,TCP握手協(xié)議完成后,Socket實(shí)例對(duì)象將創(chuàng)建完成,否則將拋出IOException錯(cuò)誤。
與之對(duì)應(yīng)的服務(wù)端將創(chuàng)建一個(gè)ServerSocket實(shí)例,ServerSocket創(chuàng)建比較簡(jiǎn)單只要指定的端口號(hào)沒(méi)有被占用,一般實(shí)例創(chuàng)建都會(huì)成功,同時(shí)操作系統(tǒng)也會(huì)為ServerSocket實(shí)例創(chuàng)建一個(gè)底層數(shù)據(jù)結(jié)構(gòu),這個(gè)數(shù)據(jù)結(jié)構(gòu)中包含指定監(jiān)聽(tīng)的端口號(hào)和包含監(jiān)聽(tīng)地址的通配符,通常情況下都是“*”即監(jiān)聽(tīng)所有地址。之后當(dāng)調(diào)用accept()方法時(shí),將進(jìn)入阻塞狀態(tài),等待客戶端的請(qǐng)求。當(dāng)一個(gè)新的請(qǐng)求到來(lái)時(shí),將為這個(gè)連接創(chuàng)建一個(gè)新的套接字?jǐn)?shù)據(jù)結(jié)構(gòu),該套接字?jǐn)?shù)據(jù)的信息包含的地址和端口信息正是請(qǐng)求源地址和端口。
這個(gè)新創(chuàng)建的數(shù)據(jù)結(jié)構(gòu)將會(huì)關(guān)聯(lián)到ServerSocket實(shí)例的一個(gè)未完成的連接數(shù)據(jù)結(jié)構(gòu)列表中,注意這時(shí)服務(wù)端與之對(duì)應(yīng)的Socket實(shí)例并沒(méi)有完成創(chuàng)建,而要等到與客戶端的三次握手完成后,這個(gè)服務(wù)端的Socket實(shí)例才會(huì)返回,并將這個(gè)Socket實(shí)例對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)從未完成列表中移到已完成列表中。所以ServerSocket所關(guān)聯(lián)的列表中每個(gè)數(shù)據(jù)結(jié)構(gòu),都代表與一個(gè)客戶端的建立的TCP連接。