Web服務可讓你在HTTP協議的基礎上經過XML或者JSON來交換信息。若是你想知道上海的天氣預報、中國石油的股價或者淘寶商家的一個商品信息,你能夠編寫一段簡短的代碼,經過抓取這些信息而後經過標準的接口開放出來,就如同你調用一個本地函數並返回一個值。javascript
Web服務背後的關鍵在於平臺的無關性,你能夠運行你的服務在Linux系統,能夠與其餘Windows的asp.net程序交互,一樣的,也能夠經過同一個接口和運行在FreeBSD上面的JSP無障礙地通訊。html
目前主流的有以下幾種Web服務:REST、SOAP。java
在不少底層網絡應用開發者的眼裏一切編程都是Socket,話雖然有點誇張,但卻也幾乎如此了,如今的網絡編程幾乎都是用Socket來編程。你想過這些情景麼?咱們天天打開瀏覽器瀏覽網頁時,瀏覽器進程怎麼和Web服務器進行通訊的呢?當你用QQ聊天時,QQ進程怎麼和服務器或者是你的好友所在的QQ進程進行通訊的呢?當你打開PPstream觀看視頻時,PPstream進程如何與視頻服務器進行通訊的呢? 如此種種,都是靠Socket來進行通訊的,以一斑窺全豹,可見Socket編程在現代編程中佔據了多麼重要的地位,這一節咱們將介紹Go語言中如何進行Socket編程。git
Socket起源於Unix,而Unix基本哲學之一就是「一切皆文件」,均可以用「打開open –> 讀寫write/read –> 關閉close」模式來操做。Socket就是該模式的一個實現,網絡的Socket數據傳輸是一種特殊的I/O,Socket也是一種文件描述符。Socket也具備一個相似於打開文件的函數調用:Socket(),該函數返回一個整型的Socket描述符,隨後的鏈接創建、數據傳輸等操做都是經過該Socket實現的。github
經常使用的Socket類型有兩種:流式Socket(SOCK_STREAM)和數據報式Socket(SOCK_DGRAM)。流式是一種面向鏈接的Socket,針對於面向鏈接的TCP服務應用;數據報式Socket是一種無鏈接的Socket,對應於無鏈接的UDP服務應用。golang
網絡中的進程之間如何經過Socket通訊呢?首要解決的問題是如何惟一標識一個進程,不然通訊無從談起!在本地能夠經過進程PID來惟一標識一個進程,可是在網絡中這是行不通的。其實TCP/IP協議族已經幫咱們解決了這個問題,網絡層的「ip地址」能夠惟一標識網絡中的主機,而傳輸層的「協議+端口」能夠惟一標識主機中的應用程序(進程)。這樣利用三元組(ip地址,協議,端口)就能夠標識網絡的進程了,網絡中須要互相通訊的進程,就能夠利用這個標誌在他們之間進行交互web
使用TCP/IP協議的應用程序一般採用應用編程接口:UNIX BSD的套接字(socket)和UNIX System V的TLI(已經被淘汰),來實現網絡進程之間的通訊。就目前而言,幾乎全部的應用程序都是採用socket,而如今又是網絡時代,網絡中進程通訊是無處不在,這就是爲何說「一切皆Socket」。ajax
經過上面的介紹咱們知道Socket有兩種:TCP Socket和UDP Socket,TCP和UDP是協議,而要肯定一個進程的須要三元組,須要IP地址和端口。編程
目前的全球因特網所採用的協議族是TCP/IP協議。IP是TCP/IP協議中網絡層的協議,是TCP/IP協議族的核心協議。目前主要採用的IP協議的版本號是4(簡稱爲IPv4),發展至今已經使用了30多年。json
IPv4的地址位數爲32位,也就是最多有2的32次方的網絡設備能夠聯到Internet上。近十年來因爲互聯網的蓬勃發展,IP位址的需求量越來越大,使得IP位址的發放愈趨緊張,前一段時間,據報道IPV4的地址已經發放完畢,咱們公司目前不少服務器的IP都是一個寶貴的資源。
地址格式相似這樣:127.0.0.1 172.122.121.111
IPv6是下一版本的互聯網協議,也能夠說是下一代互聯網的協議,它是爲了解決IPv4在實施過程當中遇到的各類問題而被提出的,IPv6採用128位地址長度,幾乎能夠不受限制地提供地址。按保守方法估算IPv6實際可分配的地址,整個地球的每平方米麪積上仍可分配1000多個地址。在IPv6的設計過程當中除了一勞永逸地解決了地址短缺問題之外,還考慮了在IPv4中解決很差的其它問題,主要有端到端IP鏈接、服務質量(QoS)、安全性、多播、移動性、即插即用等。
地址格式相似這樣:2002:c0e8:82e7:0:0:0:c0e8:82e7
這一節講了tcp編程,幸虧我以前學習過一點tcp編程的知識,否則又是啥都不知道~~~~
WebSocket是HTML5的重要特性,它實現了基於瀏覽器的遠程socket,它使瀏覽器和服務器能夠進行全雙工通訊,許多瀏覽器(Firefox、Google Chrome和Safari)都已對此作了支持。
在WebSocket出現以前,爲了實現即時通訊,採用的技術都是「輪詢」,即在特定的時間間隔內,由瀏覽器對服務器發出HTTP Request,服務器在收到請求後,返回最新的數據給瀏覽器刷新,「輪詢」使得瀏覽器須要對服務器不斷髮出請求,這樣會佔用大量帶寬。
WebSocket採用了一些特殊的報頭,使得瀏覽器和服務器只須要作一個握手的動做,就能夠在瀏覽器和服務器之間創建一條鏈接通道。且此鏈接會保持在活動狀態,你可使用JavaScript來向鏈接寫入或從中接收數據,就像在使用一個常規的TCP Socket同樣。它解決了Web實時化的問題,相比傳統HTTP有以下好處:
WebSocket URL的起始輸入是ws://或是wss://(在SSL上
WebSocket分爲客戶端和服務端,接下來咱們將實現一個簡單的例子:用戶輸入信息,客戶端經過WebSocket將信息發送給服務器端,服務器端收到信息以後主動Push信息到客戶端,而後客戶端將輸出其收到的信息,客戶端的代碼以下:
<html> <head></head> <body> <script type="text/javascript"> var sock = null; var wsuri = "ws://127.0.0.1:1234"; window.onload = function() { console.log("onload"); sock = new WebSocket(wsuri); sock.onopen = function() { console.log("connected to " + wsuri); } sock.onclose = function(e) { console.log("connection closed (" + e.code + ")"); } sock.onmessage = function(e) { console.log("message received: " + e.data); } }; function send() { var msg = document.getElementById('message').value; sock.send(msg); }; </script> <h1>WebSocket Echo Test</h1> <form> <p> Message: <input id="message" type="text" value="Hello, world!"> </p> </form> <button onclick="send();">Send Message</button> </body> </html>
能夠看到客戶端JS,很容易的就經過WebSocket函數創建了一個與服務器的鏈接sock,當握手成功後,會觸發WebSocket對象的onopen事件,告訴客戶端鏈接已經成功創建。客戶端一共綁定了四個事件。
1)onopen 創建鏈接後觸發
2)onmessage 收到消息後觸發
3)onerror 發生錯誤時觸發
4)onclose 關閉鏈接時觸發
咱們服務器端的實現以下:
package main import ( "golang.org/x/net/websocket" "fmt" "log" "net/http" ) func Echo(ws *websocket.Conn) { var err error for { var reply string if err = websocket.Message.Receive(ws, &reply); err != nil { fmt.Println("Can't receive") break } fmt.Println("Received back from client: " + reply) msg := "Received: " + reply fmt.Println("Sending to client: " + msg) if err = websocket.Message.Send(ws, msg); err != nil { fmt.Println("Can't send") break } } } func main() { http.Handle("/", websocket.Handler(Echo)) if err := http.ListenAndServe(":1234", nil); err != nil { log.Fatal("ListenAndServe:", err) } }
當客戶端將用戶輸入的信息Send以後,服務器端經過Receive接收到了相應信息,而後經過Send發送了應答信息
目前隨着HTML5的發展,我想將來WebSocket會是Web開發的一個重點,咱們須要儲備這方面的知識
RESTful,是目前最爲流行的一種互聯網軟件架構。由於它結構清晰、符合標準、易於理解、擴展方便,因此正獲得愈來愈多網站的採用。本小節咱們未來學習它究竟是一種什麼樣的架構?以及在Go裏面如何來實現它。
REST(REpresentational State Transfer)這個概念,首次出現是在 2000年Roy Thomas Fielding(他是HTTP規範的主要編寫者之一)的博士論文中,它指的是一組架構約束條件和原則。知足這些約束條件和原則的應用程序或設計就是RESTful的。
要理解什麼是REST,咱們須要理解下面幾個概念:
資源(Resources) REST是"表現層狀態轉化",其實它省略了主語。"表現層"其實指的是"資源"的"表現層"。
那麼什麼是資源呢?就是咱們日常上網訪問的一張圖片、一個文檔、一個視頻等。這些資源咱們經過URI來定位,也就是一個URI表示一個資源。
表現層(Representation)
資源是作一個具體的實體信息,他能夠有多種的展示方式。而把實體展示出來就是表現層,例如一個txt文本信息,他能夠輸出成html、json、xml等格式,一個圖片他能夠jpg、png等方式展示,這個就是表現層的意思。
URI肯定一個資源,可是如何肯定它的具體表現形式呢?應該在HTTP請求的頭信息中用Accept和Content-Type字段指定,這兩個字段纔是對"表現層"的描述。
訪問一個網站,就表明了客戶端和服務器的一個互動過程。在這個過程當中,確定涉及到數據和狀態的變化。而HTTP協議是無狀態的,那麼這些狀態確定保存在服務器端,因此若是客戶端想要通知服務器端改變數據和狀態的變化,確定要經過某種方式來通知它。
客戶端能通知服務器端的手段,只能是HTTP協議。具體來講,就是HTTP協議裏面,四個表示操做方式的動詞:GET、POST、PUT、DELETE。它們分別對應四種基本操做:GET用來獲取資源,POST用來新建資源(也能夠用於更新資源),PUT用來更新資源,DELETE用來刪除資源。
綜合上面的解釋,咱們總結一下什麼是RESTful架構:
(1)每個URI表明一種資源;
(2)客戶端和服務器之間,傳遞這種資源的某種表現層;
(3)客戶端經過四個HTTP動詞,對服務器端資源進行操做,實現"表現層狀態轉化"。
Web應用要知足REST最重要的原則是:客戶端和服務器之間的交互在請求之間是無狀態的,即從客戶端到服務器的每一個請求都必須包含理解請求所必需的信息。若是服務器在請求之間的任什麼時候間點重啓,客戶端不會獲得通知。此外此請求能夠由任何可用服務器回答,這十分適合雲計算之類的環境。由於是無狀態的,因此客戶端能夠緩存數據以改進性能。
另外一個重要的REST原則是系統分層,這表示組件沒法瞭解除了與它直接交互的層次之外的組件。經過將系統知識限制在單個層,能夠限制整個系統的複雜性,從而促進了底層的獨立性。
當REST架構的約束條件做爲一個總體應用時,將生成一個能夠擴展到大量客戶端的應用程序。它還下降了客戶端和服務器之間的交互延遲。統一界面簡化了整個系統架構,改進了子系統之間交互的可見性。REST簡化了客戶端和服務器的實現,並且對於使用REST開發的應用程序更加容易擴展
Go沒有爲REST提供直接支持,可是由於RESTful是基於HTTP協議實現的,因此咱們能夠利用net/http包來本身實現,固然須要針對REST作一些改造,REST是根據不一樣的method來處理相應的資源,目前已經存在的不少自稱是REST的應用,其實並無真正的實現REST
REST就是根據不一樣的method訪問同一個資源的時候實現不一樣的邏輯處理。
REST是一種架構風格,汲取了WWW的成功經驗:無狀態,以資源爲中心,充分利用HTTP協議和URI協議,提供統一的接口定義,使得它做爲一種設計Web服務的方法而變得流行。在某種意義上,經過強調URI和HTTP等早期Internet標準,REST是對大型應用程序服務器時代以前的Web方式的迴歸。目前Go對於REST的支持仍是很簡單的,經過實現自定義的路由規則,咱們就能夠爲不一樣的method實現不一樣的handle,這樣就實現了REST的架構。
前面幾個小節咱們介紹瞭如何基於Socket和HTTP來編寫網絡應用,經過學習咱們瞭解了Socket和HTTP採用的是相似"信息交換"模式,即客戶端發送一條信息到服務端,而後(通常來講)服務器端都會返回必定的信息以表示響應。客戶端和服務端之間約定了交互信息的格式,以便雙方都可以解析交互所產生的信息。可是不少獨立的應用並無採用這種模式,而是採用相似常規的函數調用的方式來完成想要的功能。
RPC就是想實現函數調用模式的網絡化。客戶端就像調用本地函數同樣,而後客戶端把這些參數打包以後經過網絡傳遞到服務端,服務端解包處處理過程當中執行,而後執行的結果反饋給客戶端。
RPC(Remote Procedure Call Protocol)——遠程過程調用協議,是一種經過網絡從遠程計算機程序上請求服務,而不須要了解底層網絡技術的協議。它假定某些傳輸協議的存在,如TCP或UDP,以便爲通訊程序之間攜帶信息數據。經過它可使函數調用模式網絡化。在OSI網絡通訊模型中,RPC跨越了傳輸層和應用層。RPC使得開發包括網絡分佈式多程序在內的應用程序更加容易。
Go標準包中已經提供了對RPC的支持,並且支持三個級別的RPC:TCP、HTTP、JSONRPC。但Go的RPC包是獨一無二的RPC,它和傳統的RPC系統不一樣,它只支持Go開發的服務器與客戶端之間的交互,由於在內部,它們採用了Gob來編碼。
Go已經提供了對RPC的良好支持,經過上面HTTP、TCP、JSON RPC的實現,咱們就能夠很方便的開發不少分佈式的Web應用,我想做爲讀者的你已經領會到這一點。但遺憾的是目前Go還沒有提供對SOAP RPC的支持,欣慰的是如今已經有第三方的開源實現了。
惋惜,rpc這我根本看不懂┭┮﹏┭┮,只是大概知道它是怎嘛作的
這一章咱們介紹了目前流行的幾種主要的網絡應用開發方式,第一小節介紹了網絡編程中的基礎:Socket編程,由於如今網絡正在朝雲的方向快速進化,做爲這一技術演進的基石的的socket知識,做爲開發者的你,是必需要掌握的。第二小節介紹了正愈發流行的HTML5中一個重要的特性WebSocket,經過它,服務器能夠實現主動的push消息,以簡化之前ajax輪詢的模式。第三小節介紹了REST編寫模式,這種模式特別適合來開發網絡應用API,目前移動應用的快速發展,我以爲未來會是一個潮流。第四小節介紹了Go實現的RPC相關知識,對於上面四種開發方式,Go都已經提供了良好的支持,net包及其子包,是全部涉及到網絡編程的工具的所在地
(〝▼皿▼)這一章一節比一節難,尤爲是最後一節