? ? ? ? 接下來說Java中非常重要的一個技術(shù)部分陕凹,就是網(wǎng)絡(luò)編程悍抑。Java語言涵蓋的領(lǐng)域非常廣,對于網(wǎng)絡(luò)這一塊它也不示弱杜耙,Java也可以完成網(wǎng)絡(luò)通訊的部分搜骡。
????????我們以前寫代碼是單機版的,比如把代碼從C盤拷貝到D盤佑女。那么能不能從我的機器上發(fā)條信息记靡,到張三的機器上,張三再給我回復(fù)條信息团驱,讓我們兩個機器之間利用Java語言實現(xiàn)數(shù)據(jù)的通訊摸吠,而數(shù)據(jù)通訊的原理就是數(shù)據(jù)傳輸。那么它和我們之前本機上數(shù)據(jù)傳輸?shù)奈ㄒ徊煌褪巧婕暗搅司W(wǎng)絡(luò)嚎花。
? ? ? ? 畫圖來表示一下通訊的過程:?
????02-網(wǎng)絡(luò)編程(概述2)
? ? ? ? IP地址分四段組成寸痢,每一段其實就是一個字節(jié),一個字節(jié)最大值就是255(8個1)贩幻。
? ? ? ? 有一個IP地址非常特殊,就是127.0.0.1两嘴,這個是一個本地回環(huán)地址丛楚。也就是說,本地沒有配任何IP地址的情況下憔辫,本機默認的IP地址就是127.0.0.1趣些。
? ? ? ? 可以PING它來測試網(wǎng)卡:
? ? ? ? 后面4段的IP地址已經(jīng)不夠用了(IPV4),所以就出現(xiàn)了6段的IP地址(IPV6)贰您,IPV6不光包含數(shù)字坏平,還包含字母拢操,它排列組合之后地址非常多,足夠使用了舶替。這是我們新段地址(IPV6)和老段地址(IPV4)的區(qū)別令境。
? ? ? ? 下面說端口,端口數(shù)字的選擇范圍為0-65535顾瞪。通常0-1024這個范圍內(nèi)的端口被系統(tǒng)所保留了舔庶。
????03-網(wǎng)絡(luò)編程(網(wǎng)絡(luò)模型)
? ? ? ? 說完了網(wǎng)絡(luò)傳輸?shù)幕救兀篒P地址、端口陈醒、協(xié)議以外惕橙,我們就要說一說具體的傳輸方式。
? ? ? ? 首先說一下網(wǎng)絡(luò)模型钉跷。
? ? ? ? 網(wǎng)絡(luò)在傳輸?shù)倪^程中弥鹦,因為每層次所對應(yīng)的功能不一樣,而有了層次的細致劃分爷辙。
? ? ? ? 網(wǎng)絡(luò)參考模型:
? ? ? ? 剛開始7層參考模型數(shù)據(jù)封包的過程:
? ? ? ? 數(shù)據(jù)拆包的過程:
? ? ? ? 后來有了簡化的參考模型彬坏,將應(yīng)用層、表示層犬钢、會話層合成了應(yīng)用層苍鲜,將數(shù)據(jù)鏈路層和物理層合成了主機至網(wǎng)絡(luò)層,而傳輸層和網(wǎng)絡(luò)層(網(wǎng)際層)因為比較重要依然單獨存在玷犹。簡化后的參考模型只有四層了混滔。
? ? ? ? 那我們現(xiàn)在主要學(xué)習(xí)哪一層呢?
? ? ? ? 因為我們是學(xué)軟件的歹颓,所以硬件部分主機至網(wǎng)絡(luò)層不用管坯屿,主要學(xué)應(yīng)用層、傳輸層巍扛、網(wǎng)際層领跛,其中傳輸層和網(wǎng)際層是我們學(xué)習(xí)的重點,之前我們寫的程序都在這一層撤奸。
? ? ? ? 而如果學(xué)Java Web開發(fā)的話吠昭,就主要在應(yīng)用層混。
? ? ? ? 所以說胧瓜,我們現(xiàn)在要玩的是軟件中比較底層的(傳輸層和網(wǎng)際層)矢棚,而應(yīng)用層是基于我們學(xué)的這些,就它封裝了府喳。所以應(yīng)用層更簡單蒲肋。
? ? ? ? 而每個層都有自己的協(xié)議(通訊規(guī)則),傳輸層最常見的協(xié)議就是TCP和UDP,網(wǎng)際層最常見的協(xié)議就是IP兜粘,應(yīng)用層最常見的協(xié)議就是HTTP和FTP申窘。
? ? ? ? 我們接下來的計劃是,先學(xué)網(wǎng)際層和傳輸層孔轴,掌握它們的特點后剃法,再學(xué)應(yīng)用層。
????04-網(wǎng)絡(luò)編程(IP地址)
? ? ? ? 我們知道網(wǎng)絡(luò)通訊有三個要素:IP地址距糖、端口號玄窝、傳輸協(xié)議。那么如何用Java來操作它呢悍引?我們想到了封裝成對象恩脂。
? ? ? ? 先來看一下這幾個要素的特點。
? ? ? ? IP地址:
? ? ? ? 1趣斤,是網(wǎng)絡(luò)中設(shè)備的標識俩块。
? ? ? ? 2,不易記憶浓领,可用主機名玉凯。
? ? ? ? 3,本地回環(huán)地址:127.0.0.1? 主機名:localhost
? ? ? ? 主機名和IP地址是相對應(yīng)的联贩,每臺計算機都有自己的主機名:
? ? ? ? 那么IP到底用什么來表示呢漫仆?
? ? ? ? 我們來java.net包中看一看。
? ? ? ? net包中用于描述IP的對象是InetAddress泪幌,它有兩個子類盲厌,“4”和“6”:
? ? ? ? 打印本地的主機名和地址:
? ? ? ? 還可以用非靜態(tài)的方法單獨獲取主機名和地址:
? ? ? ? 有沒有辦法獲取任意一臺主機的主機名和地址呢?
? ? ? ? 我們想一想,如果存在這個方法祸泪,那么這個方法的返回值類型是IP地址對象(即InetAddress)吗浩,另外任意一臺主機的話,為了清除到底是哪一臺没隘,必須將這臺主機指定進去傳進去懂扼,所以這個方法還需要有參數(shù)。分析得到這兩個要素右蒲,我們在方法中找一找有沒有符合則兩個要素的方法阀湿。
? ? ? ? 我們看到一個,傳入主機名返回IP地址對象的:
? ? ? ? 代碼演示:
? ? ? ? 可是這里我們還是用自己的本機試的瑰妄,我們試試其他機子:
? ? ? ? 運行的很慢:
? ? ? ? 如果這個地址和它對應(yīng)的主機名沒有在網(wǎng)絡(luò)上陷嘴,那么拿這個地址出去找就沒有解析成功。那為什么我們本機的可以解析這個不能解析呢翰撑?因為本機的信息本機上都有罩旋,而另外一臺機子的信息沒有找到,所以返回的主機名還是IP地址眶诈。
? ? ? ? 其實只要連上網(wǎng)涨醋,我們可以直接獲取百度主機名和地址(不用寫它的IP地址,直接寫它的域名就好了逝撬,它就和IP地址相對應(yīng))浴骂,可是百度面向的人群那么大,它肯定有多臺主機宪潮,而且一個地址有可能對應(yīng)著多個服務(wù)器溯警,所以有可能返回來的IP對象不唯一,所以這里還有一個傳入主機名返回數(shù)組的方法:
????05-網(wǎng)絡(luò)編程(TCP和UDP)? ? ? ?
? ? ? ? 端口號:
? ? ? ? 1狡相,是用于標識進程的邏輯地址梯轻,不同進程的標識。
? ? ? ? 2尽棕,有效端口:0~65535喳挑,其中0~1024為系統(tǒng)使用或保留端口。
? ? ? ? 端口就是一個數(shù)字標識滔悉,所以它沒有必要封裝成對象伊诵。
? ? ? ? 下面重點說一下傳輸協(xié)議。
? ? ? ? 傳輸協(xié)議:
? ? ? ? 1回官,它是通訊的規(guī)則曹宴。
? ? ? ? 2,常見協(xié)議:TCP歉提,UDP笛坦。
? ? ? ? TCP和UDP到底有什么區(qū)別呢?
? ? ? ? UDP是面向無連接的唯袄,將數(shù)據(jù)封裝包中弯屈,然后貼上小紙條,標明它的地址和端口恋拷。一般傳輸都有兩端:發(fā)送端和接收端资厉,如果用UDP傳輸,那么對方在不在都無所謂蔬顾,我就是發(fā)我的宴偿,把數(shù)據(jù)打成一個包發(fā)出去,你在就收到了诀豁,不在這個包就丟掉窄刘。另外,在傳輸?shù)臅r候也可能存在地址不存在的情況舷胜。
? ? ? ? UDP的特點:
? ? ? ? 1娩践,將數(shù)據(jù)及源和目的封裝在數(shù)據(jù)包中,不需要建立連接。
? ? ? ? 2翻伺,每個數(shù)據(jù)包的大小限制在64k內(nèi)材泄。
? ? ? ? 3,因無連接吨岭,是不可靠協(xié)議拉宗,容易丟包。
? ? ? ? 4辣辫,不需要建立連接旦事,速度快。
? ? ? ? 我們聊天急灭、視頻共享就是UDP姐浮,在不在不重要,把數(shù)據(jù)發(fā)出去就行了葬馋。
? ? ? ? 下面說TCP单料,TCP必須是面向連接的。也就是說点楼,如果用TCP通訊的話扫尖,對方必須在,對方不在就不行掠廓。它比較可靠换怖,如果單方面斷開的話,數(shù)據(jù)就不傳了蟀瞧。必須形成通路沉颂,數(shù)據(jù)才能傳輸。
? ? ? ? 那怎么確認對方在不在呢悦污?
? ? ? ? 我們通過三次握手來完成铸屉。
? ? ? ? TCP的特點:
? ? ? ? 1,建立連接切端,形成傳輸數(shù)據(jù)的通道彻坛。
? ? ? ? 2,在連接中進行大數(shù)據(jù)量傳輸踏枣。
? ? ? ? 3昌屉,通過三次握手完成連接,是可靠協(xié)議茵瀑。
? ? ? ? 4间驮,必須建立連接,效率會稍低马昨。
? ? ? ? TCP相當(dāng)于打電話竞帽,只有對方接電話才能通話扛施。
????06-網(wǎng)絡(luò)編程(Socket)
? ? ? ? 下面說Socket,我們說的網(wǎng)絡(luò)編程屹篓,其實就是Socket編程煮嫌。
? ? ? ? Socket就是為網(wǎng)絡(luò)服務(wù)提供的一種機制。
? ? ? ? 通信的兩端都有Socket抱虐,有了Socket才能建立連接。它就相當(dāng)于碼頭饥脑,有了碼頭恳邀,船只才能在兩個碼頭間通行、搬運貨物灶轰。
? ? ? ? 網(wǎng)絡(luò)通信其實就是Socket間的通信。
? ? ? ? 數(shù)據(jù)在兩個Socket間通過IO傳輸笋颤。
????07-網(wǎng)絡(luò)編程(Udp-發(fā)送端)
? ? ? ? Socket有了赋除,但是傳輸協(xié)議不同喉悴,每個傳輸協(xié)議都有自己建立端點的方式嘀粱。
? ? ? ? 我們先來說UDP的Socket服務(wù)的建立。
? ? ? ? 我們看到j(luò)ava.net包中有兩個socket對象,一個叫DatagramSocket:
? ? ? ? 這個對象既能發(fā)送又能接收宋税,如果有兩個端點發(fā)送和接收數(shù)據(jù)乏屯,那這兩個端點每個端點都要有這個對象根时。
? ? ? ? 那么發(fā)送和接收什么數(shù)據(jù)是不是就要指定一下呢:
? ? ? ? UDP要把數(shù)據(jù)封裝成包發(fā)過去,其中包括擴對方的地址和端口辰晕、自己的地址和端口蛤迎,都在這個數(shù)據(jù)包中,這個數(shù)據(jù)包很復(fù)雜含友,所以把這個數(shù)據(jù)包封裝成了對象替裆,這個對象就是DatagramPacket:
????????接下來要寫代碼,我們的需求是:
????????代碼:
????????不要忘記導(dǎo)入包:
? ? ? ? 因為面向無連接窘问,所以這個數(shù)據(jù)就丟失了辆童,那怎么能夠讓這個數(shù)據(jù)被收到呢?
????08-網(wǎng)絡(luò)編程(Udp-接收端)
? ? ? ? 之所以數(shù)據(jù)丟失是因為接收端沒開南缓,我們這節(jié)課來寫接收端的代碼,為了看起來更直觀就將接收端代碼和發(fā)送端代碼寫在同一個java文件中了荧呐,但是它們是兩段獨立運行的程序汉形,所以里面都有自己的主函數(shù)。
? ? ? ? 接收端的需求和思路:
? ? ? ? 定義udpsocket服務(wù)的時候倍阐,通常會監(jiān)聽一個端口概疆,其實就是給這個接收網(wǎng)絡(luò)應(yīng)用程序定義數(shù)字標識,方便于明確哪些數(shù)據(jù)過來該應(yīng)用程序可以處理峰搪。
? ? ? ? 代碼:
? ? ? ? 接下來要運行了岔冀,開啟兩個dos命令行:
? ? ? ? 這里的1093是系統(tǒng)隨機為發(fā)送端產(chǎn)生的數(shù)字標識(在我們沒有為發(fā)送端指定數(shù)字標識的前提下):
? ? ? ? 多運行幾次我們發(fā)現(xiàn)每一次都不一樣:
????????若我們?yōu)榘l(fā)送端指定了數(shù)字標識8888:
? ? ? ? 則這里就會顯示我們指定的數(shù)字標識,不用系統(tǒng)隨機分配了:
????09-網(wǎng)絡(luò)編程(UDP-鍵盤錄入方式數(shù)據(jù))
? ? ? ? 在這里加上while(true)循環(huán):
? ? ? ? 我們在這里加上while(true)循環(huán)的好處是概耻,接收端運行的時候運行一次就OK了使套,因為receive方法是阻塞式方法梳码,它會一直等著纯出,我們運行一次之后它就一直等著兴泥,每次一有數(shù)據(jù)傳輸過來它都可以接收到朵耕,實現(xiàn)了重復(fù)接收:
????????但是我們發(fā)現(xiàn)老師每次發(fā)送的都是同一句話瓮顽,能不能發(fā)送點別的呢射窒?
????????那我們把這里改一下重新編譯運行發(fā)送畔勤?
? ? ? ? 可是每次只能發(fā)一句珊搀,而且每發(fā)一句就要重新編譯運行夯尽,好麻煩呢瞧壮。
? ? ? ? 那我們能不能通過鍵盤錄入呢?
? ? ? ? 代碼:
? ? ? ? 運行效果:
? ? ? ? 我們剛剛用的地址是192.168.1.254匙握,最后一段的取值中0和255比較特別咆槽,192.168.1.0代表這一個網(wǎng)絡(luò)段,而192.168.1.255是這一個網(wǎng)絡(luò)段的廣播地址圈纺,就是給這個網(wǎng)絡(luò)段的所有地址讀發(fā)送罗晕。
? ? ? ? 改成這個地址就可以實現(xiàn)群聊了:
????10-網(wǎng)絡(luò)編程(UDP-聊天)
? ? ? ? 我們剛剛的效果是仿造的聊天济欢,但是是在兩個窗口實現(xiàn),能不能一個窗口實現(xiàn)呢小渊?
? ? ? ? 這個時候就要用到多線程的技術(shù)法褥,一個線程控制收,一個線程控制發(fā)酬屉。
? ? ? ? 因為收和發(fā)動作是不一致的半等,所以要定義兩個run方法,而且這兩個方法要封裝到不同的類中呐萨。
? ? ? ? 記得導(dǎo)入這兩個包:
? ? ? ? 運行效果:
? ? ? ? 但是有一個問題谬擦,我們正在寫數(shù)據(jù)還沒有回車發(fā)送的時候,如果地方此時發(fā)送了一條消息就會出現(xiàn)下面的問題谜悟,和我們正在編輯的數(shù)據(jù)混在一起:
? ? ? ? 這都是因為北秽,發(fā)送端和接收端混在同一個面積區(qū)域中,如果我們做一個圖形化界面贺氓,將發(fā)送端和接收端分成兩個區(qū)域,就解決了這個問題辙培。
????11-網(wǎng)絡(luò)編程(TCP傳輸)
? ? ? ? 說完了UDP傳輸蔑水,我們說TCP傳輸。
? ? ? ? 實在好著急扬蕊,下面是純截屏肤粱,好著急好著急。
? ? ? ? 演示TCP傳輸:
????12-網(wǎng)絡(luò)編程(TCP傳輸2)
? ? ? ? 剛才只是客戶端給服務(wù)端發(fā)了信息厨相,但是服務(wù)端并沒有給客戶端反饋领曼,下面我們要實現(xiàn)反饋動作。
? ? ? ? 需求描述和實現(xiàn)步驟:
? ? ? ? 代碼:
? ? ? ? 運行結(jié)果:
????13-網(wǎng)絡(luò)編程(TCP練習(xí))
? ? ? ? 接下來通過一個練習(xí)來用到開發(fā)中常用到的對象蛮穿。
? ? ? ? 需求描述:? ? ? ??
? ? ? ? 代碼:
? ? ? ? 運行之后發(fā)現(xiàn)客戶端發(fā)信息庶骄,服務(wù)端并不能收到。是哪里出問題了呢践磅?
? ? ? ? 首先单刁,考慮一下客戶端到底發(fā)出去了沒有呢??
? ? ? ? 客戶端的數(shù)據(jù)寫入了緩沖區(qū),在這里恍然大悟羔飞,剛剛忘記寫flush了肺樟,我們把flush加上。
? ? ? ? 另一個問題就是服務(wù)端讀數(shù)據(jù)判斷結(jié)束的標記是換行標記:
? ? ? ? 而客戶端發(fā)送數(shù)據(jù)后面并沒有換行標記逻淌,于是我們再加上換行符田柔,修改后的代碼如下:
? ? ? ? 運行擎鸠,服務(wù)端收到了客戶端的數(shù)據(jù)袜蚕,但是客戶端并沒有收到服務(wù)端返回的大寫數(shù)據(jù)糊饱。
? ? ? ? 我們又忘記給服務(wù)端flush了滞项,因為它的數(shù)據(jù)也是寫在緩沖區(qū)中呢,另外戏仓,和服務(wù)端一樣,客戶端判斷數(shù)據(jù)結(jié)束的標記也是換行符仁热,所以我們也加上換行符举哟,代碼修改如下(和剛剛客戶端代碼添加的內(nèi)容是一樣的):
? ? ? ? 運行:
? ? ? ? 該例子中出現(xiàn)的問題:
? ? ? ? 另外诬乞,這個例子中的還有可以簡化的代碼森瘪,客戶端和服務(wù)端簡化的部分都一樣,這里以服務(wù)端部分示例:
????14-網(wǎng)絡(luò)編程(TCP復(fù)制文件)
? ? ? ? 剛才的例子是通過鍵盤錄入,從客戶端向服務(wù)端發(fā)數(shù)據(jù)军俊。下面再說一個例子,將客戶端的數(shù)據(jù)發(fā)送到服務(wù)端镰官,再由服務(wù)端將數(shù)據(jù)存到一個文件中去,這就相當(dāng)于數(shù)據(jù)拷貝笨腥。
? ? ? ? 以前是將文件從C盤拷到D盤,現(xiàn)在是將文件從我的機子中拷到你的機子中镶奉,其中加入了網(wǎng)絡(luò)的技術(shù),但是還是IO玻侥。
? ? ? ? 代碼:
? ? ? ? 記得導(dǎo)包哦:
? ? ? ? 但是程序一直停不下來姑食,沒有像我們預(yù)料中那樣出現(xiàn)上傳成功的文字:
? ? ? ? 但是我們?nèi)ノ募A重看了一下,發(fā)現(xiàn)文件已經(jīng)成功存入了呢。
? ? ? ? 原來斥铺,是因為代碼中沒有結(jié)束標記邻眷,于是我們在客戶端的代碼中组力,在文件中數(shù)據(jù)全部讀取完畢之后腥椒,加上結(jié)束標記“over”:
? ? ? ? 在服務(wù)端中判斷結(jié)束標記“over”蛉鹿,若碰到則結(jié)束:
? ? ? ? 但是如果這個文件中本身就正好包含“over”领追,和我們的結(jié)束標記“over”重名了怎么辦呢?
? ? ? ? 不如我們用下面這串字符:
? ? ? ? 但即使是這串字符,這種定義方式也是容易重復(fù)的,我們用一個唯一的標記:時間戳葬燎,因為每個時刻的時間是唯一的。
? ? ? ? 注意壕探,在客戶端代碼中厉熟,發(fā)送數(shù)據(jù)之前需要先將時間戳發(fā)給服務(wù)端导盅,讓它知道這是結(jié)束標記,然后客戶端中讀完了源文件的數(shù)據(jù)揍瑟,再在后面補上時間戳作為結(jié)束標記白翻,下面是客戶端和服務(wù)端代碼的修改,客戶端:
? ? ? ? 服務(wù)端:
? ? ? ? 其實绢片,這還是一個比較麻煩的方法滤馍,我們只是做一下了解(好氣喔!)
? ? ? ? 其實有更簡單的方法,而且只需要修改客戶端中的代碼倦炒,且只用加上這一句代碼:
? ? ? ? OK:
? ? ? ? day23的課程實在太倉促了,好著急栋盹,所以好多都用截屏了收壕,也沒有聽的很細致枪蘑,好慚愧瞻鹏。
? ? ? ? 這兩天好難受,宿舍和實驗室都空蕩蕩的粤策,一個人待在實驗室學(xué)習(xí),其實注意力好難集中,因為真的很難受,但是蒿辙,一切都會過去的,小楠楠加油(;′⌒`)?
? ? ? ? 現(xiàn)在是21:27屿聋,宿管阿姨讓我早點回宿舍,因為外面很黑甫煞,也沒有人岔留,她說很危險诸衔,我要快速去外面吃個飯然后回宿舍诊霹,我心里羞延,好怕喔(;′⌒`)?
? ? ? ? 小楠楠要加油F⒒埂0槁帷!