關於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
&
&& &&&&&&百度一下,你就知道&& & & & & & & & & & &

& & & & & &&&&&&& & & & & &新聞& &hao123& &地圖& &視頻& &貼吧& & &登錄& & &document.write("&登錄&");
&
&更多產品& & & & & & &

&關於百度& &About Baidu& & &

copy;2017nbsp;Baidunbsp;&使用百度前必讀  &意見反饋 京ICP證030173號nbsp; & & & & & & &

那些什麼html, css神馬的你可以先不過管,是給瀏覽器去解釋的。

你也可以把輸出重定向到/dev/null,順面列印下HTTP(s)協議的header和相關信息。如下:

$ curl https://www.baidu.com -svo /dev/null
* Rebuilt URL to: https://www.baidu.com/
* Trying 14.215.177.39...
* TCP_NODELAY set
* Connected to www.baidu.com (14.215.177.39) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* CAfile: /etc/pki/tls/certs/ca-bundle.crt
CApath: none
* ALPN, server accepted to use http/1.1
* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate:
* subject: CN=baidu.com,OU=service operation department.,O="BeiJing Baidu Netcom Science Technology Co., Ltd",L=beijing,ST=beijing,C=CN
* start date: Jun 29 00:00:00 2017 GMT
* expire date: Aug 17 23:59:59 2018 GMT
* common name: baidu.com
* issuer: CN=Symantec Class 3 Secure Server CA - G4,OU=Symantec Trust Network,O=Symantec Corporation,C=US
&> GET / HTTP/1.1
&> Host: www.baidu.com
&> User-Agent: curl/7.51.0
&> Accept: */*
&>
&< HTTP/1.1 200 OK &< Accept-Ranges: bytes &< Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform &< Connection: Keep-Alive &< Content-Length: 2443 &< Content-Type: text/html &< Date: Wed, 08 Nov 2017 14:19:09 GMT &< Etag: "58860402-98b" &< Last-Modified: Mon, 23 Jan 2017 13:24:18 GMT &< Pragma: no-cache &< Server: bfe/1.0.8.18 &< Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/ &< { [1048 bytes data] * Curl_http_done: called premature == 0 * Connection #0 to host www.baidu.com left intact

strace

然後你再用strace來列印curl過程中的所有系統調用,只需要關注和socket相關的系統調用即可。如果你有自己的web server環境可以測試,做個簡單http網頁自己測試一下比較好理解。如下是strace一個只輸出Hello world文字的頁面的結果,沒有任何格式。相關的系統調用如下,從字面上應該很好理解:

// IP address: xxx.xxx.xxx.xxx
$ strace -s 300 curl http://xxx.xxx.xxx.xxx/welcome.html
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("xxx.xxx.xxx.xxx")}, 16) = -1 EINPROGRESS (Operation now in progress)
sendto(3, "GET /welcome.html HTTP/1.1
Host: xxx.xxx.xxx.xxx
User-Agent: curl/7.51.0
Accept: */*

", 89, MSG_NOSIGNAL, NULL, 0) = 89
recvfrom(3, "HTTP/1.1 200 OK
Server: nginx/1.10.2
Date: Wed, 08 Nov 2017 14:25:25 GMT
Content-Type: text/html
Content-Leng th: 14
Last-Modified: Wed, 08 Nov 2017 14:25:04 GMT
Connection: keep-alive
ETag: "5a0313c0-e"
Accept-Ranges: bytes

Hello, world!
", 16384, 0, NULL, NULL) = 249
write(1, "Hello, world!
", 14Hello, world!) = 14

補充一下,最後一行與socket讀寫無關,只是curl這個進程向標準輸出(fd=1, 終端)寫的結果,所以你在屏幕上能看到這行輸出。


對協議棧驅動節點的操作。即對V節點的操作。即對文件的讀寫。元數據為SKB。


推薦今天在看的Linux高性能網路編程,雖然我是學java的,不過看這本書,覺得還是神書,講得很透徹,關於TCP,ip的控制,覺得java的netty神框架也是這裡面的半同步半非同步思想


樓主你沒有很好的理解分層實現的概念。換個角度來說明這個問題。
假如你在上海,要寄送個快遞到廣州,
你要做的事情
1.把快遞打包
2.填寫快遞單上的收件人 地址 聯繫電話
3.叫順豐過來取件,付款
過一兩天快遞就到了收件人手上

你會發現事情如此之簡單,完全不用考慮別的。
實際上你付款之後發生了好多事情
快遞員的手持終端錄入快遞單信息
把快遞帶回集散中心 裝車/上飛機
路上還有很複雜的流程
到達目的地之後還有派送環節
中間還有很多監控管理環節

可是你寄送快遞 這些流程你都不用去考慮
這不代表不需要這些流程,因為有人幫你做了

當然 你也可以自己去實現 整個流程。
也就是說你可以自己寫一個瀏覽器試一試。
平時用java C# Python寫網路交互的程序為什麼不用考慮socket?因為有人都寫好了這些庫,你只是調用。

如果讓你用socket tcp/udp 寫一個兩台電腦之間文件傳輸的程序,你慢慢就會明白 不用自己直接調用socket真爽啊!


問:url和socket關係
答:寫完url,按回車,瀏覽器將url轉換成一個HTTP請求報(就是一堆字元串),通過socket發出去

問:啥時候會用到socket編程
答:自定義應用層的時候。應用層其實是沒聽上去高大上,類似於對個口號,比如:座山雕座山雕,我當前坐標是xxxx,請告訴我你的坐標。這樣的報文其實也是可以的。
網路可遠不止http,儘管這是普通人最多接觸的。像一些遊戲就直接用socket,還有MySQL,各種NoSQL可能都有自定義的應用層socket吧


http服務在應用層,底層還是要socket發送的,socket說白了也就是把TCP或UDP協議封裝了一下,提供給你API。


你可以理解成瀏覽器(客戶端)通過url建立socket鏈接(socket connect),然後瀏覽器根據http協議向這個socket寫特定的數據(write),比如

GET / HTTP/1.1
Host:http://www.bing.com

然後伺服器就根據協議回一堆東西(客戶端 read),瀏覽器根據協議去解析,然後渲染出來呈現給你


推薦閱讀:

怎樣看待小米 Note 3 現貨發售後,迄今為止官網仍供貨充足?
奧迪除了燈和quattro之外還有什麼技術是拿的出手的?
如果羅永浩造汽車會是什麼樣子?
如何看待中國航天科工:我國正研究時速4000公里超級列車?
為什麼小米商店單日下載量高達5000萬,而蘋果僅僅800萬?

TAG:科技 | 計算機科學 | IT行業 | 網路協議 |