
前言
介于自己的網(wǎng)絡(luò)方面知識爛的一塌糊涂,所以準(zhǔn)備寫相關(guān)網(wǎng)絡(luò)的文章,但是考慮全部寫在一篇太長了,所以分開寫,希望大家能仔細(xì)看,最好可以指出我的錯誤,讓我也能糾正。
1.講解相關(guān)的整個網(wǎng)絡(luò)體系結(jié)構(gòu):
Android技能樹 — 網(wǎng)絡(luò)小結(jié)(1)之網(wǎng)絡(luò)體系結(jié)構(gòu)
2.講解相關(guān)網(wǎng)絡(luò)的重要知識點,比如很多人都聽過相關(guān)網(wǎng)絡(luò)方面的名詞,但是僅限于聽過而已,什么tcp ,udp ,socket ,websocket, http ,https ,然后webservice是啥,跟websocket很像,socket和websocket啥關(guān)系長的也很像,session,token,cookie又是啥。
Android技能樹 — 網(wǎng)絡(luò)小結(jié)(2)之TCP/UDP
Android技能樹 — 網(wǎng)絡(luò)小結(jié)(3)之HTTP/HTTPS
Android技能樹 — 網(wǎng)絡(luò)小結(jié)(4)之socket/websocket/webservice
相關(guān)網(wǎng)絡(luò)知識點小結(jié)- cookie/session/token(待寫)
3.相關(guān)的第三方框架的源碼解析,畢竟現(xiàn)在面試個大點的公司,okhttp和retrofit源碼是必問的。
Android技能樹 — 網(wǎng)絡(luò)小結(jié)(6)之 OkHttp超超超超超超超詳細(xì)解析
Android技能樹 — 網(wǎng)絡(luò)小結(jié)(7)之 Retrofit源碼詳細(xì)解析
正文
1. Socket
我們在網(wǎng)絡(luò)體系結(jié)構(gòu)小結(jié)中提過,TCP/IP的體系結(jié)構(gòu)圖為
在傳輸層中為TCP和UDP,解決了數(shù)據(jù)之間的運(yùn)輸,但是我們很少直接去調(diào)用TCP和UDP,比如我們現(xiàn)在是要用TCP傳輸數(shù)據(jù),你要寫代碼去進(jìn)行TCP的三次握手連接和四次揮手?jǐn)嚅_等,而且可能還要考慮什么滑動窗口,累積確認(rèn)、分組緩存、流量控制等?所以我們正需要某個類,這個類幫我們封裝好了TCP的連接,傳輸,斷開等一系列相關(guān)各類操作,是不是就很方便了。沒錯,這個類就是Socket。
Socket 即套接字,是應(yīng)用層 與 TCP/IP 協(xié)議族通信的中間軟件抽象層,表現(xiàn)為一個封裝了 TCP / IP協(xié)議族 的編程接口(API)
1.Socket不是一種協(xié)議,而是一個編程調(diào)用接口(API),屬于傳輸層(主要解決數(shù)據(jù)如何在網(wǎng)絡(luò)中傳輸)</br>
2.即:通過Socket,我們才能在Andorid平臺上通過 TCP/IP協(xié)議進(jìn)行開發(fā)</br>
3.對用戶來說,只需調(diào)用Socket去組織數(shù)據(jù),以符合指定的協(xié)議,即可通信
關(guān)于Socket的使用,代碼一搜一大把,這里我就快速通過,直接講一下大致代碼流程,我們知道現(xiàn)在是為了把一個信息從一臺設(shè)備到另外一臺設(shè)備,在網(wǎng)絡(luò)體系結(jié)構(gòu)小結(jié)中提過IP是用來確定信息最后到哪個目標(biāo)設(shè)備,所以我們一定要知道IP,到了目標(biāo)設(shè)備后,目標(biāo)設(shè)備可能開啟了很多應(yīng)用程序(多個進(jìn)程),這時候怎么知道這個數(shù)據(jù)包到哪個進(jìn)程呢,這里也會涉及到端口,我們平常寫代碼,有時候是不是會說某個端口被占用了。所以我們同時除了ip還要知道端口。
所以初步是設(shè)備A的ip,設(shè)備A的端口,設(shè)備B的ip,設(shè)備B的端口,換成我們平常的通俗說法就是客戶端ip,客戶端端口,服務(wù)端ip,服務(wù)端端口,外加上我們的Socket用來操作TCP,同時也可以操作 UDP,所以同時還有一個協(xié)議。所以最終涉及到這5個元素,socket 通過這5個元素來確定。
具體的Socket代碼就不多說了:
客戶端:
public class ClientSocket {
public static void main(String args[]) {
String host = "127.0.0.1";
int port = 8919;
try {
Socket client = new Socket(host, port);
Writer writer = new OutputStreamWriter(client.getOutputStream());
writer.write("Hello From Client");
writer.flush();
writer.close();
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
服務(wù)端:
public class Server {
public static void main(String args[]) {
ServerSocket echoServer = null;
String line;
DataInputStream is;
PrintStream os;
Socket clientSocket = null;
try {
echoServer = new ServerSocket(9999);
}
catch (IOException e) {
System.out.println(e);
}
try {
clientSocket = echoServer.accept();
is = new DataInputStream(clientSocket.getInputStream());
os = new PrintStream(clientSocket.getOutputStream());
// As long as we receive data, echo that data back to the client.
while (true) {
line = is.readLine();
os.println(line);
}
} catch (IOException e) {
System.out.println(e);
}
}
}
看了代碼,我們發(fā)現(xiàn)Socket的一個很大的特點就是服務(wù)端和客戶端可以相互傳數(shù)據(jù)。這和我們平時的網(wǎng)絡(luò)交互差別挺大的,畢竟我們平常訪問后臺接口,很少說后臺突然通過這個接口發(fā)個數(shù)據(jù)給客戶端是吧,一般都是客戶端主動發(fā)送接口請求,然后才能拿到相關(guān)數(shù)據(jù)。
2. WebSocket
我們在上面的Socket的相關(guān)介紹可以看到,Socket是在運(yùn)輸層做了一層抽象層,是TCP/UDP 的 api工具類,所以Socket不算是應(yīng)用層類,而我們在相關(guān)網(wǎng)絡(luò)知識點小結(jié)- http/https提過Http/Https是屬于應(yīng)用層的,而我們的WebSocket也是屬于應(yīng)用層的。所以說WebSocket和Http/Https是同一層級的。
而我們也經(jīng)??吹胶芏嗨^的Http與WebSocket的區(qū)別文章等,比如:
而我們在上面介紹Socket的時候提過,Socket可以雙向通信,所以WebSocket也是可以雙向通信的,而在沒有雙向通信的時候,用Http來進(jìn)行雙向通信更多的是使用長輪詢。
在WebSocket API尚未被眾多瀏覽器實現(xiàn)和發(fā)布的時期,開發(fā)者在開發(fā)需要接收來自服務(wù)器的實時通知應(yīng)用程序時,不得不求助于一些“hacks”來模擬實時連接以實現(xiàn)實時通信,最流行的一種方式是長輪詢。長輪詢主要是發(fā)出一個HTTP請求到服務(wù)器,然后保持連接打開以允許服務(wù)器在稍后的時間響應(yīng)(由服務(wù)器確定)。為了這個連接有效地工作,許多技術(shù)需要被用于確保消息不錯過,如需要在服務(wù)器端緩存和記錄多個的連接信息(每個客戶)。雖然長輪詢是可以解決這一問題的,但它會耗費(fèi)更多的資源,如CPU、內(nèi)存和帶寬等,要想很好的解決實時通信問題就需要設(shè)計和發(fā)布一種新的協(xié)議。
WebSocket 是伴隨HTML5發(fā)布的一種新協(xié)議。它實現(xiàn)了瀏覽器與服務(wù)器全雙工通信(full-duplex),可以傳輸基于消息的文本和二進(jìn)制數(shù)據(jù)
WebSocket和長輪詢之間的帶寬消耗差異:
而WebSocket連接的時候,也會用到http,因為在最剛開始發(fā)出連接請求的時候,也是要借助于現(xiàn)有的HTTP協(xié)議,當(dāng)連接成功后,其他時候直接基于TCP完成通信。
1.首先,客戶端發(fā)起http請求,經(jīng)過3次握手后,建立起TCP連接;http請求里存放WebSocket支持的版本號等信息,如:Upgrade、Connection、WebSocket-Version等;</br>2.然后,服務(wù)器收到客戶端的握手請求后,同樣采用HTTP協(xié)議回饋數(shù)據(jù);</br>3.最后,客戶端收到連接成功的消息后,開始借助于TCP傳輸信道進(jìn)行全雙工通信。
當(dāng)然如果只是了解大概的WebSocket和Http的區(qū)別,可以看這篇:WebSocket的原理,以及和Http的關(guān)系,用了通俗易懂的例子說明了,更加好記,但是并沒有說明具體的詳細(xì)內(nèi)容。
詳細(xì)的可以看看這篇:
【騰云閣】WebSocket 淺析
那我們既然是安卓開發(fā),那我們怎么樣使用WebSocket呢,我想現(xiàn)在很多人都應(yīng)該網(wǎng)絡(luò)請求這塊使用的是Okhttp吧,雖然我們平時就是用Okhttp做簡單的http/https請求,但其實它也是支持WebSocket的,具體大家可以直接搜索相關(guān)文章
image
3. WebService
首先如果有人做過相關(guān)的 WebService 的話,就會覺得大體上其實和平常的 http 請求差不多,都是發(fā)送一個請求,然后接受相應(yīng)的返回數(shù)據(jù),可能最直觀的差別是平常我們用 http 發(fā)送請求,接收到請求/響應(yīng)報文中的請求體都是 JSON,而WebService用的是 XML 的形式。其實的確是這樣,因為Webservice就是采用了基于http的soap協(xié)議傳輸數(shù)據(jù),所以簡單理解為soap=http+xml。因為用了xml之后,更加的通用性,對于跨平臺跨應(yīng)用來說都更好的相互通信解析。
XML+XSD,SOAP和WSDL就是構(gòu)成WebService平臺的三大技術(shù)。
我們具體一項項來查看:
3.1 XML+XSD
WebService采用HTTP協(xié)議傳輸數(shù)據(jù),采用XML格式封裝數(shù)據(jù)(即XML中說明調(diào)用遠(yuǎn)程服務(wù)對象的哪個方法,傳遞的參數(shù)是什么,以及服務(wù)對象的 返回結(jié)果是什么)。XML是WebService平臺中表示數(shù)據(jù)的格式。除了易于建立和易于分析外,XML主要的優(yōu)點在于它既是平臺無關(guān)的,又是廠商無關(guān) 的。無關(guān)性是比技術(shù)優(yōu)越性更重要的:軟件廠商是不會選擇一個由競爭對手所發(fā)明的技術(shù)的。
XSD又是什么呢,因為我們平常寫xml格式的內(nèi)容,可以隨便寫,只要符合基本的xml格式就行,但實際上這樣就沒有一套標(biāo)準(zhǔn)的數(shù)據(jù)類型了。所以XML Schema(XSD)就是專門解決這個問題的一套標(biāo)準(zhǔn)。它定義了一套標(biāo)準(zhǔn)的數(shù)據(jù)類型,并給出了一種語言來擴(kuò)展這套數(shù)據(jù)類型
3.2 SOAP
WebService通過HTTP協(xié)議發(fā)送請求和接收結(jié)果時,發(fā)送的請求內(nèi)容和結(jié)果內(nèi)容都采用XML格式封裝,并增加了一些特定的HTTP消息頭,以說明 HTTP消息的內(nèi)容格式,這些特定的HTTP消息頭和XML內(nèi)容格式就是SOAP協(xié)議。SOAP提供了標(biāo)準(zhǔn)的RPC方法來調(diào)用Web Service。
所以 SOAP協(xié)議 = HTTP協(xié)議 + XML數(shù)據(jù)格式
3.3 WSDL
使用過WebService應(yīng)該都知道這個,WebService務(wù)器端首先要通過一個WSDL文件來說明有啥服務(wù)可以對外調(diào)用,服務(wù)是什么(服務(wù)中有哪些方法,方法接受 的參數(shù)是什么,返回值是什么),服務(wù)的網(wǎng)絡(luò)地址用哪個url地址表示,服務(wù)通過什么方式來調(diào)用。
比如下面這個是國內(nèi)手機(jī)號碼歸屬地查詢WEB服務(wù):
而且提供了soap1.1/soap1.2/get/post 四種方式來調(diào)用獲?。?/p>
但是實際上可能沒有寫的這么詳細(xì),就是給我們一個WSDL,里面的內(nèi)容是這樣的:
這里有些人可能不知道怎么來讀懂這個文件,其實很簡單,我們一步步來看:
-
我們先找到相應(yīng)的service:
image
我們可以看到里面有soap1.1,soap1.2, http-get,http-post四種,我們以soap1.2為例,我們可以看到她后面binding = "tns:MobileCodeWSSoap12",所以我們查找相應(yīng)的binding的值 -
我們搜索到了
MobileCodeWSSoap12后發(fā)現(xiàn)是:
所以我們要繼續(xù)跟蹤下去,這下查找的是imagetype="tns:MobileCodeWSSoap" -
我們搜索關(guān)鍵字:
tns:MobileCodeWSSoap后發(fā)現(xiàn)的是:
我們可以看到image<wsdl:operation name="getMobileCodeInfo">,所以我們知道方法名字叫getMobileCodeInfo,同時下面有<wsdl:input message="tns:getMobileCodeInfoSoapIn"/> 和 <wsdl:output message="tns:getMobileCodeInfoSoapOut"/>
看字面意思就知道是輸入?yún)?shù)和輸出參數(shù),然后繼續(xù)對應(yīng)關(guān)鍵字getMobileCodeInfoSoapIn和getMobileCodeInfoSoapOut搜下 -
搜到的結(jié)果為:
,然后繼續(xù)跟蹤imagegetMobileCodeInfo和getMobileCodeInfoResponse。 -
最終看到了具體的輸入?yún)?shù)和輸出參數(shù)。
明顯輸入?yún)?shù)是imagemobileCode和userID,輸出參數(shù)是getMobileCodeInfoResult,而且都是字符串類型。
總體來說就是
<service>-><binding>-><type>-><message>-><element>
那么另外一個問題來了,我們從哪里得到WSDL呢?
WSDL 文件保存在Web服務(wù)器上,通過一個url地址就可以訪問到它。客戶端要調(diào)用一個WebService服務(wù)之前,要知道該服務(wù)的WSDL文件的地址。比如上面我貼圖的WSDL內(nèi)容就是只要訪問:http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?WSDL就可以了。
WebService服務(wù)提供商可以通過兩種方式來暴露它的WSDL文件地址:1.注冊到UDDI服務(wù)器,以便被人查找;2.直接告訴給客戶端調(diào)用者。
補(bǔ)充1 :可能有些人會說WSDL的內(nèi)容還是看不懂,可以參考 WSDL 教程 及 WebService中的WSDL詳細(xì)解析 學(xué)習(xí)。
image
補(bǔ)充2 : 剛提到了Soap1.1 和 Soap1.2:
image
image
image
結(jié)語:
emmmm.......輕噴即可。有錯請留言,我可以進(jìn)行修改。其中文章配圖部分引自下面參考文章。
參考文章:
Android:這是一份很詳細(xì)的Socket使用攻略
WebSocket詳解(四):刨根問底HTTP與WebSocket的關(guān)系(上篇)
WebService學(xué)習(xí)總結(jié)(一)——WebService的相關(guān)概念