關於socket的困惑???
「」socket是一種"打開—讀/寫—關閉"模式的實現,伺服器和客戶端各自維護一個"文件",在建立連接打開後,可以向自己文件寫入內容供對方讀取或者讀取對方內容,通訊結束時關閉文件。「」
這就是說,客戶端和伺服器各有一個socket,伺服器的socket保持監聽的狀態,客戶端的socket可以在send()裡面寫入東西,然後在伺服器對應的socket接到客戶端socket傳來的請求和內容,進行讀取,和對應的寫入響應。那也就是說,socket就是應用層和傳輸層之間的一個抽象,它的一組封裝了的tcp的介面,通過調用這些介面的api就可以實現網路通訊而不用那些原始的繁雜的操作。
那我想,我們平時瀏覽器和伺服器交互,無論是地址欄直接寫url,還是ajax,還是form表單提交,還是a標籤,還是window.location.href 這些,不都是直接寫一個url基本就可以實現了,好像也沒有那些繁雜的操作呀?這些操作比如說直接地址欄寫個url回車獲取頁面和socket有關係嗎?socket具體什麼時候會用到呢?什麼時候需要具體寫socket api進行編程呢?
首先我想說的是,題主的思考、理解是對的,甚至超過大多數人對Socket的理解,這裡先為題主贊一記,提出了一個我經常思索,經常翻書的經典問題,今天分享一下我對這個話題的理解。
凡是對文件操作過的同學,都應該知道,讀取/寫入一個文件通常會有以下操作:
1)
文件handler = Open(文件絕對路徑,文件名稱)
2)
Read(文件handler)or
Write(文件handler,改寫內容)
3)
Close(文件handler)
全球億億萬萬用戶通過文件瀏覽器,打開/修改文件的動作,最後都會轉化為以上三個API函數,但是99%+以上的用戶無需關心這些抽象的函數,因為文件瀏覽器已經提供了圖形界面給用戶,用戶只需左鍵單擊、雙擊即可完成。
這是操作系統內核給應用程序(比如文件瀏覽器,當然還有千千萬萬用戶程序)提供的介面函數,如果沒有這些介面函數,應用程序則需要和硬碟控制器打交道,要在程序里實現非常多的代碼,來讀取扇區中的數據,應用程序的程序員要精通這些底層硬體操作,這不是一個科學的流程。
需要操作系統將這些繁雜的工作全部攬下,把底層操作抽象為一個個用戶友好的介面函數,這樣應用程序的編製就非常簡單明了。
熟悉Socket 編程的同學,看到文件操作會大吃一斤,原來和socket 編程是如此地相似,請看:
1)
socket_handler= Socket(, , Destination IP/ Port)
2)
Send(socket_handler,Data)or
Recv(socket_handler,size)
3)
Close(socket_handler)
只要有一點編程基礎的同學,編寫個socket通信絕對沒有問題。
這些socket函數是操作系統內核將「TCP/IP協議棧 + 底層網卡」抽象出來的一個個用戶友好的函數,用於操縱本地的「TCP/IP協議棧 + 底層網卡」與遠端的伺服器/主機完成通信的任務。
題主提到了http是否可以不使用TCP socket,是否可以直接調用網卡的介面函數,自己將http請求打包好發給網卡?可以的,一點問題沒有,但至少需要源IP、目的IP,否則如何跨越Internet到達對端?好,現在達成了共識,至少還需要IP地址,意味著應用程序發給網卡的數據至少有IP + http了。
但如何保證「IP + http」在傳輸過程中不丟、不亂序,如何知道對端一定是活著的(在線),IP是不夠智能的,只會簡單運送,無法解決丟包重傳、重新排序、流量控制等複雜的動作,所以我們還需要在http里實現可靠傳輸,時刻盯著自己發出的包,超時就重傳;對數據包編號,可以根據編號來對亂序的包重新排序,同學們,這些功能是否似曾相識?因為這就是TCP份內的事,既然已經有了這個簡單易行的工具,為何要重開爐灶?另外TCP協議有N多程序猿的貢獻,經歷了全球億萬萬用戶的考驗,性能、可靠性可能要比私有的實現更好、更快、更強!
如果想通過socket操縱Ethernet 、IP、TCP里的一些協議欄位,如 Source MAC、ToS、TTL、TCP Option,也是可以的,需要調用Raw Socket即可。
用socket 實現http, 你的疑惑就解決了,看太多書,不與寫幾行代碼。
樓主首先要了解tcp/ip協議族。我們在瀏覽器瀏覽網頁時是使用的HTTP協議。HTTP是應用層協議,其本質也是一個TCP。
至於為什麼你沒有處理socket就能上網了,。這個很好理解。因為瀏覽器幫你做了。請注意區分用戶和程序員的區別。作為用戶,我們使用網路產品,比如瀏覽器,比如聊天軟體,比如網遊客戶端。其中都有socket的處理,但是你不能指望用戶去操作這些。
不論是你說的地址欄輸入URL,還是js的location。其本質都是因為有瀏覽器。表徵一個socket就是ip以及埠。在地址欄輸入的URL,經過DNS,會解析出ip ,而埠通常就是HTTP的80以及HTTPS的443,另外你也可以顯式指定埠。
另外樓主問什麼時候使用socket API編程。最顯而易見的就是瀏覽器(或其他網路客戶端)和web伺服器的開發者。另外還有很多需要自定義通信協議的地方,比如企業內部的後台通信。
當然通常這些工作在企業內部只有少數人參與,進行通信框架的開發。大多數人都是使用框架編寫業務邏輯。
遠程文件不好理解,咱們就拿本地文件來理解。
你平常讀磁碟上的文件,沒有指定讀哪個塊,而是根據文件名去找內容。這是因為編程語言在磁碟讀取 API 上為你封裝了文件 API。
其實本地文件系統也有很多層。首先是磁碟上的物理塊,然後他們封裝為控制塊(inode)和數據塊,然後它們又封裝成了文件。
遠程也是如此。因為 HTTP 協議在 TCP 基礎上實現,編程語言就把 Socket API 給你封裝成了 Web API,你自然就不用管那些那些東西了。
你對Socket的理解有誤,以及你對網路模型的理解有誤,你所引用的文字的描述也不甚清楚,雖然不能說錯,但是卻沒有指明關鍵點即Socket運作在何種層面上。
首先複習一下網路分層模型:
應用層
表達層
會話層
-----------------------上三層現在基本被統一,不需要加以嚴格區分,可以統稱為應用層
傳輸層
-----------------------規定如何傳輸數據
網路層
-----------------------規定如何將數據正確傳輸到目標
鏈路層
-----------------------規定如何建立、保持和釋放網路中的數據單元
物理層
-----------------------規定如何構建物理數據通路
Socket是從應用層直到網路層的一個縱向的封裝,根據不同的模式來在不同層面上運行。
當我們需要實現應用層的協議時(HTTP/FTP/DNS等),我們建立基於傳輸層的Socket(SOCK_STREAM或Sock_DRAM),即指定該協議運行於哪種傳輸層協議之上。
當我們需要實現傳輸層的協議時(TCP/UDP等)或者更低層級(如網路層),我們建立基於鏈路層的Socket(SOCK_RAW)
你所提到的東西,比如輸入url,是應用層之上高層實現,和SOCKET中間至少隔了一大層,有可能隔了更多層。
舉個例子,當你輸入url的時候,系統到底都做了些什麼呢?
1. 調用DNS,把這個URL解析為IP地址
2. 應用層(HTTP等)決定發送的數據包的格式和內容,下放給傳輸層
3. 傳輸層將包拆封成若干幀,根據傳輸層協議,將各幀下放給網路層
4. 網路層解析IP地址,尋找合適的發送目標,下方給鏈路層
5. 鏈路層定位正確的目標單元,將數據簇下方給物理層
6. 物理層將數據轉化為光/電信號,發送給目標單元
7. 目標單元接受信號,合併成數據,上傳給鏈路層
8. 鏈路層合併數據簇,上傳給網路層
9. 網路層檢查地址,如果自己不是目標地址,重複步驟4,否則繼續
10. 如果自己是目標地址,上傳給傳輸層,
11. 傳輸層檢查數據幀頭,確保數據是正確按順序接受且無遺失,在接受到全部幀後合併成完全數據包,上傳給應用層
12. 應用層解析數據包,執行數據包要求的指令
13. 執行完成,生成回包,重複步驟2
如他名字所述,他真的就是個插座,用電的和發電的都不用管他背後被封裝的實現有多複雜
這正是網路協議的作用啊,http工作在應用層,屏蔽了很多傳輸層的細節,作為前端程序員,正是瀏覽器幫你屏蔽了socket的種種繁瑣。
所以最好理解的方法就是不用瀏覽器去瀏覽一個網頁,那用啥?命令行。題主想問的是socket,那麼我們撇去dhcp,arp這些,直接從telnet開始(curl動作都做得太多了)
我們看philippica是咋瀏覽網頁的。
有一天philippica想看以前寫的一篇解題報告,要打開頁面:http://www.cnblogs.com/philippica/ (https的頁面增加了一層ssl,不贅述),但是尷尬的是電腦上沒裝瀏覽器。
我首先要知道http://www.cnblogs.com這個域名對應的IP是啥
我們通過查找DNS伺服器知道了對應的IP為101.37.225.65
接下來我們鏈接到伺服器,http服務的默認埠是80,telnet抽象了三次握手等細節,現在通過telnet,我們登錄到了cnblogs這台伺服器上
好,現在到了HTTP協議的地方,它有很多請求類型,常見的有GET,POST,CONNECT,PUT DELETE這些,我們現在要獲取伺服器上的一個html文件(index.html),用的是get方法,對於TCP,我們要明白的最重要的一點是,它是stream而不是packet(對應UDP),也就是我們是和伺服器對話。
HTTP協議是基於ASCII的協議,所以直接就可以在telnet中敲。不妨用HTTP1.1協議,它支持keep-alive。
我們要取伺服器上/philippica目錄下的資源,協議是HTTP1.1,方法是GET,Host是http://www.cnblogs.com,根據HTTP協議,我們構造了以下的字元串:
GET /philippica/ HTTP/1.1
Host: www.cnblogs.com
然後一行回車(
),我們得到了以下東西
首先是回復的頭,
HTTP/1.1 200 OK
Date: Wed, 08 Nov 2017 15:34:06 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 17015
Connection: keep-alive
Vary: Accept-Encoding
Cache-Control: private, max-age=10
Expires: Wed, 08 Nov 2017 15:34:15 GMT
Last-Modified: Wed, 08 Nov 2017 15:34:05 GMT
X-UA-Compatible: IE=10
X-Frame-Options: SAMEORIGIN
這個就是在Chrome 里network抓包能看到的最左邊一欄header,200 OK表示 正確的回應。
接下來根據協議是兩行
,再下面便是我們請求的資源(html文件),很幸運,伺服器沒有gzip壓縮這個html,我們可以直接看到html的源碼。
還沒完呢,正如前面所說,TCP是stream,也就是像打電話一樣,你說一句,我說一句。剛才我向伺服器請求/philippica資源,伺服器回給我了這個html,接下來又是我說了。
我們看到伺服器和我們協商的欄位:Connection: keep-alive,伺服器打算keep-alive,也就是我們可以減少三次握手的開銷,在這次對話中把需要的資源全部得到。
例如我們可以看到我們剛得到的index.html里有個&標籤,對應圖片的src是
www.cnblogs.com/images/xml.gif,
同一個伺服器下images/xml.gif的資源,我們也是通過GET去獲得這張圖片
GET /images/xml.gif HTTP/1.1
Host: www.cnblogs.com
回到原題,題主說不了解輸入url,ajax,form表單提交和socket的關係,但是實際上瀏覽器就是在做著我上面的工作,一次次的發送字元,收到字元的過程,直到把整個網頁需要的圖片,js,css下載完畢,並且渲染出來的過程。既然不了解瀏覽器做了什麼,不妨像我這樣嘗試從telnet或者自己寫個socket程序與伺服器交互獲取所有的文件,這樣能更深的熟悉http協議,keep-alive,socket等過程
可以把 socket 看作一個管道,這個管道里可以流通數據,瀏覽器中使用的 HTTP 協議可以看作是用來規範數據格式的,只有按照這種格式來傳輸,對方才能明白要表達的意思。瀏覽器或 HTTP Client 封裝好了處理這類數據的方法,所以通常情況下你不需要直接用到 socket。什麼時候才需要用 socket 呢,就是當你想用自己的方式(比如通過某些特定的位元組來替代 HTTP Header 來壓縮流量)傳輸數據的時候,就可以直接通過 socket。
實際上 TCP 和 UDP socket 也是被操作系統封裝好的一類 socket,想接觸更底層的可以直接使用 raw socket,你可以自己組裝發送至網卡的 packet,當然,這種需求會更少。
推薦看一下圖解tcp或者相關計算機網路的書。
瀏覽器和WEB伺服器交互是通過HTTP協議來進行的,說白了,Ajax實際上也是在訪問一個HTTP地址。
再者,瀏覽器底層通信都是通過Socket來實現的,Socket只負責發送和接收數據,至於數據包結構就是不同的上層協議(如HTTP協議或者FTP協議)來自行規定的。題主你好,看了你的回答終於知道socket是什麼了。。我該說什麼好,謝謝你~
題主,既然已經知道了,一個url再回車,可以獲取一個頁面,不妨再深入了解下,這個url是如何發送給伺服器的,伺服器又是如何把頁面發送給瀏覽器的。
這種類似的文章很多了,隨便貼一個哈,侵刪
http://edusagar.com/articles/view/70/What-happens-when-you-type-a-URL-in-browser
注意這裡面提到的tcp鏈接。題主應該對http協議有一定了解。http 協議是基於tcp協議的
在這裡,socket就是對tcp的一層抽象,讓程序可以方便地讀寫tcp流
除非你直接用TCP或UDP,或需要極高的Performance和Scalability,Socket基本上可以不懂了。其實Socket API很簡單,五分鐘就看完了,難的是制定自己的協議,但也不算很難,看你想做什麼。一般能用HTTP完成,就使用HTTP,畢竟防火牆預設不擋,安裝無需嚴密審核,軟體也會好賣很多,別自找麻煩。
對了,看了網上大多工作要求,還有不少Socket Programming。其實只要能答題就好,真正能搞Socket的很少,別聽大家放屁。當然咯,如果你必須寫操作系統,資料庫,遊戲引擎或一些協議優化,你就必須懂Socket。等你到那個水平,Socket是世界上最簡單的事。
如果想要了解從訪問url到調用socket的過程,用瀏覽器不太直觀。建議用命令行工具curl看,並且同時用strace抓去curl的系統調用(socket和socket相關操作系統調用)。這個過程和瀏覽器訪問的過程在系統調用和HTTP/TCP協議層面是一樣的,只是沒有對格式的封裝和解釋,界面不友好(其實是沒有界面),主要用於測試。
curl
curl的輸出如下:
$ curl https://www.baidu.com
&
&& &&&&&&