1. 程式人生 > 實用技巧 >16 . Go之網路程式設計

16 . Go之網路程式設計

網際網路的本質

兩臺計算機之間的通訊與兩個人打電話原理是一樣的.

# 1. 首先要通過各種物理連線介質連線
# 2. 找準確對方計算機(準確到軟體)的位置
# 3. 通過統一的標準(一般子協議)進行資料的轉發

# 物理連線介質,這個是網路工程師所考慮的,後面也會給大家簡單的講到,咱們主要就是學習這統一的標準。

# 英語成為世界上所有人通訊的統一標準,如果把計算機看成分佈於世界各地的人,那麼連線兩臺計算機之間的internet實際上就是一系列統一的標準,這些標準稱之為網際網路協議,網際網路的本質就是一系列的協議,總稱為‘網際網路協議’(Internet Protocol Suite).

# 網際網路協議的功能:定義計算機如何接入internet,以及接入internet的計算機通訊的標準。

自從網際網路誕生以來,現在基本上所有的程式都是網路程式,很少有單機版的程式了.

計算機網路就是把各個計算機連線到一起,讓網路中的計算機可以互相通訊。網路程式設計就是如何在程式中實現兩臺計算機的通訊。

舉個例子,當你使用瀏覽器訪問新浪網時,你的計算機就和新浪的某臺伺服器通過網際網路連線起來了,然後,新浪的伺服器把網頁內容作為資料通過網際網路傳輸到你的電腦上。

由於你的電腦上可能不止瀏覽器,還有QQ、Skype、Dropbox、郵件客戶端等,不同的程式連線的別的計算機也會不同,所以,更確切地說,網路通訊是兩臺計算機上的兩個程序之間的通訊。比如,瀏覽器程序和新浪伺服器上的某個Web服務程序在通訊,而QQ程序是和騰訊的某個伺服器上的某個程序在通訊。

TCP/IP簡介

雖然大家現在對網際網路很熟悉,但是計算機網路的出現比網際網路要早很多。

計算機為了聯網,就必須規定通訊協議,早期的計算機網路,都是由各廠商自己規定一套協議,IBM、Apple和Microsoft都有各自的網路協議,互不相容,這就好比一群人有的說英語,有的說中文,有的說德語,說同一種語言的人可以交流,不同的語言之間就不行了。

為了把全世界的所有不同型別的計算機都連線起來,就必須規定一套全球通用的協議,為了實現網際網路這個目標,網際網路協議簇(Internet Protocol Suite)就是通用協議標準。Internet是由inter和net兩個單詞組合起來的,原意就是連線“網路”的網路,有了Internet,任何私有網路,只要支援這個協議,就可以聯入網際網路。

因為網際網路協議包含了上百種協議標準,但是最重要的兩個協議是TCP和IP協議,所以,大家把網際網路的協議簡稱TCP/IP協議。

通訊的時候,雙方必須知道對方的標識,好比發郵件必須知道對方的郵件地址。網際網路上每個計算機的唯一標識就是IP地址,類似123.123.123.123。如果一臺計算機同時接入到兩個或更多的網路,比如路由器,它就會有兩個或多個IP地址,所以,IP地址對應的實際上是計算機的網路介面,通常是網絡卡

​ IP協議負責把資料從一臺計算機通過網路傳送到另一臺計算機。資料被分割成一小塊一小塊,然後通過IP包傳送出去。由於網際網路鏈路複雜,兩臺計算機之間經常有多條線路,因此,路由器就負責決定如何把一個IP包轉發出去。IP包的特點是按塊傳送,途徑多個路由,但不保證能到達,也不保證順序到達。

  IP地址實際上是一個32位整數(稱為IPv4),以字串表示的IP地址如`192.168.0.1`實際上是把32位整數按8位分組後的數字表示,目的是便於閱讀。

  IPv6地址實際上是一個128位整數,它是目前使用的IPv4的升級版,以字串表示類似於`2001:0db8:85a3:0042:1000:8a2e:0370:7334`。

  TCP協議則是建立在IP協議之上的。TCP協議負責在兩臺計算機之間建立可靠連線,保證資料包按順序到達。TCP協議會通過握手建立連線,然後,對每個IP包編號,確保對方按順序收到,如果包丟掉了,就自動重發。

  許多常用的更高階的協議都是建立在TCP協議基礎上的,比如用於瀏覽器的HTTP協議、傳送郵件的SMTP協議等。

  一個TCP報文除了包含要傳輸的資料外,還包含源IP地址和目標IP地址,源埠和目標埠。

  埠有什麼作用?在兩臺計算機通訊時,只發IP地址是不夠的,因為同一臺計算機上跑著多個網路程式。一個TCP報文來了之後,到底是交給瀏覽器還是QQ,就需要埠號來區分。每個網路程式都向作業系統申請唯一的埠號,這樣,兩個程序在兩臺計算機之間建立網路連線就需要各自的IP地址和各自的埠號。

  一個程序也可能與多個計算機建立連結,因此他會申請很多埠.

  ​	瞭解了TCP/IP協議的基本概念,IP地址和埠的概念,我們就可以開始進行網路程式設計了。

軟體開發架構

CS架構,BS架構

客戶端英文名稱:Client,

瀏覽器英文名稱:Browser.

服務端英文名稱:Server.

C/S架構:基於客戶端與使用者端之間的架構。例如:QQ、微信、優酷、暴風影音等等。

  • 優點:C/S架構的介面和操作非常豐富滿足客戶的個性化要求,安全性很容易保證,響應速度較快。
  • 缺點:需要開發客戶端和伺服器兩套程式,開發成本維護成本較高,相容性差,使用者群固定等。

B/S架構:基於C/S架構的一種特殊的C/S架構,瀏覽器與服務端之間的架構。

  • 優點:分佈性強,客戶端幾乎無需維護,開發簡單,共享性強,維護簡單方便。
  • 缺點:個性化低,安全性以及響應速度需要花費巨大設計成本。

小結:CS響應速度快,安全性強,一般應用於區域網中,但是開發維護成本高;BS可以實現跨平臺,客戶端零維護,但是個性化能力低,響應速度較慢。所以有些單位日常辦公應用BS,在實際生產中使用CS結構。

# C/S 架構
	C: 客戶端
	S: 服務端

# B/S 架構
	B: 瀏覽器
	S: 服務端
        
# C/S架構:  需要安裝一下才能使用
# 		client  客戶端:  我們用的  需要安裝的
# 		server	服務端

# B/S架構: 百度 部落格園 谷歌 碼雲
# 		browser	瀏覽器
# 		server	伺服器

# b/s和c/s什麼關係?
# B/S架構是C/S架構的一種

# C/S架構的好處
# 	可以離線使用/功能更完善/安全性更好

# B/S架構
# 	不用安裝就可以使用
# 	統一PC端使用者的入口

# 手機端: 好像C/S架構比較火,其實不然,微信小程式,支付寶第三方介面都類似於B/S架構
# 目的都在於統一介面: 聚集使用者群

# PC端: BS比較火
# 本質: B/S架構本身也是C/S架構

客戶端與服務端概念

# 服務端: 24小時不間斷提供服務,誰來我就服務誰
# 客戶端: 想體驗服務的時候,就去找服務端體驗服務

學習網路程式設計能幹什麼

# 開發C/S架構的軟體

學習併發,資料庫,前端能幹什麼

# 開發B/S架構的軟體

網路程式設計技術起源

# 絕大部分先進技術的興起基本來自於軍事,網路程式設計這項技術來源於美國軍事,為了實現資料的遠端傳輸.

人類實現遠端溝通交流的方式

# 插電話線的電話
# 插網線的大屁股電腦
# 插無線網絡卡的膝上型電腦

# 綜上我們能夠總結出第一個規律:要想實現遠端通訊第一個需要具備的條件就是: 物理連線介質
# 再來想人與人之間交流,中國人說中文,外國人說外語,
# 那如果想實現不同國家的人之間無障礙溝通交流是不是得規定一個大家都能聽得懂的語言>>>英語
# 再回來看計算機領域,計算機之間要想實現遠端通訊除了需要有物理連線介質之外是不是也應該有一套公共的標準?這套標準就是
# >>>OSI七層協議(也叫OSI七層模型)

OSI七層協議(模型)

# 應用層
# 表示層
# 會話層
# 傳輸層
# 網路層
# 資料鏈路層
# 物理連線層

# 也有人將其歸納為五層
# 應用層
# 傳輸層
# 網路層
# 資料鏈路層
# 物理連線層
物理層

物理層由來: 上面提到,孤立的計算機之間要想一起玩,就必須接入internet,言外之意就是計算機之間必須完成組網.

物理層功能: 主要是基於電路特性發送高低電壓(電訊號),高電壓對應數字1,低電壓對應數字0

# 實現計算機之間物理連線,傳輸的資料都是010101的二進位制
# 電訊號工作原理: 點只有高低電平

光纖

雙絞線

資料鏈路層

資料鏈路層由來: 單純的電訊號0和1沒有任何意義,必須規定電訊號多少位一組,每組什麼意思.

資料鏈路層的功能: 定義了電訊號的分組方式

乙太網協議

早期的時候各個公司都有自己的分組方式,後來形成了統一的標準,即乙太網協議ethernet

ethernet規定

一組電訊號構成一個數據豹,叫做‘幀’

每一資料幀分成:報頭head和資料data兩部分

Head Data
報頭 資料
# head包含:(固定18個位元組)
    # 傳送者/源地址,6個位元組
	# 接收者/目標地址,6個位元組
	# 資料型別,6個位元組
    
# data包含: (最短46位元組,最長1500位元組)
	# 資料包的具體內容
# head長度 + data長度 = 最短64位元組,最長1518位元組,超過限制就分片傳送

mac地址

head中包含的源和目標地址由來:ethernet規定接入internet的裝置都必須具備網絡卡,傳送端和接收端的地址便是指網絡卡的地址,即mac地址

mac地址:每塊網絡卡出廠時都被燒製上一個世界唯一的mac地址,長度為48位2進位制,通常由12位16進位制數表示(前六位是廠商編號,後六位是流水線號)

廣播

有了mac地址,同一網路內的兩臺主機就可以通訊了(一臺主機通過arp協議獲取另外一臺主機的mac地址)

ethernet採用最原始的方式,廣播的方式進行通訊,即計算機通訊基本靠吼

# 1. 規定了二進位制資料的分組方式
# 2. 規定了只要是接入網際網路的計算機,都必須有一塊網絡卡
# 網絡卡上刻有世界唯一的編號
# 每塊網絡卡出廠時都會被燒製上一個世界上唯一的mac地址
#  長度為48位2進位制,通常由12位16進位制數表示(前六位是廠商編號,後六位是流水線號)   
#  我們管網絡卡上刻有的編號叫電腦的>>>mac地址  
#  —–>上面的兩個規定其實就是 “乙太網協議”!

# 基於乙太網協議通訊: 通訊基本靠吼!!!  弊端: 廣播風暴
# 交換機: 如果沒有交換機,你的電腦就變成了馬蜂窩,有了交換機吼,所有的電腦只需要一個網絡卡連線交換機,即可實現多臺電腦之間物理連線
網路層

網路層由來:有了ethernet、mac地址、廣播的傳送方式,世界上的計算機就可以彼此通訊了,問題是世界範圍的網際網路是由

一個個彼此隔離的小的區域網組成的,那麼如果所有的通訊都採用乙太網的廣播方式,那麼一臺機器傳送的包全世界都會收到,

這就不僅僅是效率低的問題了,這會是一種災難

上圖結論:必須找出一種方法來區分哪些計算機屬於同一廣播域,哪些不是,如果是就採用廣播的方式傳送,如果不是,

就採用路由的方式(向不同廣播域/子網分發資料包),mac地址是無法區分的,它只跟廠商有關

網路層功能:引入一套新的地址用來區分不同的廣播域/子網,這套地址即網路地址

IP協議:

  • 規定網路地址的協議叫ip協議,它定義的地址稱之為ip地址,廣泛採用的v4版本即ipv4,它規定網路地址由32位2進製表示
  • 範圍0.0.0.0-255.255.255.255
  • 一個ip地址通常寫成四段十進位制數,例:172.16.10.1

ip地址分成兩部分

  • 網路部分:標識子網
  • 主機部分:標識主機

注意:單純的ip地址段只是標識了ip地址的種類,從網路部分或主機部分都無法辨識一個ip所處的子網

例:172.16.10.1與172.16.10.2並不能確定二者處於同一子網

子網掩碼

所謂”子網掩碼”,就是表示子網路特徵的一個引數。它在形式上等同於IP地址,也是一個32位二進位制數字,它的網路部分全部為1,主機部分全部為0。比如,IP地址172.16.10.1,如果已知網路部分是前24位,主機部分是後8位,那麼子網路掩碼就是11111111.11111111.11111111.00000000,寫成十進位制就是255.255.255.0。

知道”子網掩碼”,我們就能判斷,任意兩個IP地址是否處在同一個子網路。方法是將兩個IP地址與子網掩碼分別進行AND運算(兩個數位都為1,運算結果為1,否則為0),然後比較結果是否相同,如果是的話,就表明它們在同一個子網路中,否則就不是。

比如,已知IP地址172.16.10.1和172.16.10.2的子網掩碼都是255.255.255.0,請問它們是否在同一個子網路?兩者與子網掩碼分別進行AND運算,

172.16.10.1:10101100.00010000.00001010.000000001

255255.255.255.0:11111111.11111111.11111111.00000000

AND運算得網路地址結果:10101100.00010000.00001010.000000001->172.16.10.0

172.16.10.2:10101100.00010000.00001010.000000010

255255.255.255.0:11111111.11111111.11111111.00000000

AND運算得網路地址結果:10101100.00010000.00001010.000000001->172.16.10.0

結果都是172.16.10.0,因此它們在同一個子網路。

總結一下,IP協議的作用主要有兩個,一個是為每一臺計算機分配IP地址,另一個是確定哪些地址在同一個子網路。

ip資料包

ip資料包也分為head和data部分,無須為ip包定義單獨的欄位,直接放入乙太網包的data部分

head:長度為20到60位元組

data:最長為65,515位元組。

而乙太網資料包的”資料”部分,最長只有1500位元組。因此,如果IP資料包超過了1500位元組,它就需要分割成幾個乙太網資料包,分開發送了。

乙太網頭 ip 頭 ip資料

ARP協議

arp協議由來:計算機通訊基本靠吼,即廣播的方式,所有上層的包到最後都要封裝上乙太網頭,然後通過乙太網協議傳送,在談及乙太網協議時候,我門瞭解到

通訊是基於mac的廣播方式實現,計算機在發包時,獲取自身的mac是容易的,如何獲取目標主機的mac,就需要通過arp協議

arp協議功能:廣播的方式傳送資料包,獲取目標主機的mac地址

協議工作方式:每臺主機ip都是已知的

例如:主機172.16.10.10/24訪問172.16.10.11/24

一:首先通過ip地址和子網掩碼區分出自己所處的子網

場景 資料包地址
同一子網 目標主機mac,目標主機ip
不同子網 閘道器mac,目標主機ip

二:分析172.16.10.10/24與172.16.10.11/24處於同一網路(如果不是同一網路,那麼下表中目標ip為172.16.10.1,通過arp獲取的是閘道器的mac)

源mac 目標mac 源ip 目標ip 資料部分
傳送端主機 傳送端mac FF:FF:FF:FF:FF:FF 172.16.10.10/24 172.16.10.11/24 資料

三:這個包會以廣播的方式在傳送端所處的自網內傳輸,所有主機接收後拆開包,發現目標ip為自己的,就響應,返回自己的mac

# 規定了計算機都必須有一個ip地址  
# ip地址特點:點分十進位制  
# 有兩個版本ipv4和ipv6 為了能夠相容更多的計算機  
# 最小:0.0.0.0  
# 最大:255.255.255.255  
# IP協議可以跨區域網傳輸
# ip地址能夠唯一標識網際網路中獨一無二的一臺機器!
# [http://14.215.177.39/](http://14.215.177.39/)
傳輸層(埠協議)

傳輸層的由來:網路層的ip幫我們區分子網,乙太網層的mac幫我們找到主機,然後大家使用的都是應用程式,你的電腦上可能同時開啟qq,暴風影音,等多個應用程式,

那麼我們通過ip和mac找到了一臺特定的主機,如何標識這臺主機上的應用程式,答案就是埠,埠即應用程式與網絡卡關聯的編號。

傳輸層功能:建立埠到埠的通訊

補充:埠範圍0-65535,0-1023為系統佔用埠

tcp協議:

可靠傳輸,TCP資料包沒有長度限制,理論上可以無限長,但是為了保證網路的效率,通常TCP資料包的長度不會超過IP資料包的長度,以確保單個TCP資料包不必再分割。

乙太網頭 ip 頭 tcp頭 資料

tcp報文

tcp三次握手和四次揮手

udp協議:

不可靠傳輸,”報頭”部分一共只有8個位元組,總長度不超過65,535位元組,正好放進一個IP資料包。

乙太網頭 ip頭 udp頭 資料
# TCP,UDP基於埠工作的協議!  
# 其實計算機之間通訊其實是計算機上面的應用程式於應用之間的通訊  
# 埠(port):唯一標識一臺計算機上某一個基於網路通訊的應用程式  
# 埠範圍:0~~65535(動態分配)  
# 注意:0~~1024通常是歸作業系統分配的埠號  
# 通常情況下,我們寫的軟體埠號建議起在8000之後  
# flask框架預設埠5000  
# django框架預設埠8000  
# mysql資料庫預設埠3306  
# redis資料庫預設埠6379  
# 注意:一臺計算機上同一時間一個埠號只能被一個應用程式佔用

# 小總結:  
# IP地址:唯一標識全世界接入網際網路的獨一無二的機器  
# port埠號:唯一標識一臺計算機上的某一個應用程式  
# ip+port :能夠唯一標識全世界上獨一無二的一臺計算機上的某一個應用程式

# 補充:  
# arp協議:根據ip地址解析mac地址
應用層(HTTP協議,FTP協議)

應用層由來:使用者使用的都是應用程式,均工作於應用層,網際網路是開發的,大家都可以開發自己的應用程式,資料多種多樣,必須規定好資料的組織形式

應用層功能:規定應用程式的資料格式。

例:TCP協議可以為各種各樣的程式傳遞資料,比如Email、WWW、FTP等等。那麼,必須有不同協議規定電子郵件、網頁、FTP資料的格式,這些應用程式協議就構成了”應用層”。

TCP\UDP協議(流式協議,可靠協議)
# 三次握手四次揮手
# 三次握手建連線
# 四次揮手斷連線

# Tcp(語音聊天/視訊聊天),線下快取高強電影\QQ遠端控制
# 需要先建立連線,然後才能通訊
# 佔用連線\可靠(訊息不會丟失)\實時性高\慢

# UDP(發訊息) - 線上播放視訊\QQ發訊息\微信訊息
# 不需要建立連線,就可以通訊
# 不佔用連線\不可靠\訊息因為網路不穩定丟失\快
網路通訊實現

想實現網路通訊,每臺主機需具備四要素

  • 本機的IP地址
  • 子網掩碼
  • 閘道器的IP地址
  • DNS的IP地址

獲取這四要素分兩種方式

1.靜態獲取

即手動配置

2.動態獲取

通過dhcp獲取

乙太網頭 ip頭 udp頭 dhcp資料包

(1)最前面的”乙太網標頭”,設定發出方(本機)的MAC地址和接收方(DHCP伺服器)的MAC地址。前者就是本機網絡卡的MAC地址,後者這時不知道,就填入一個廣播地址:FF-FF-FF-FF-FF-FF。

(2)後面的”IP標頭”,設定發出方的IP地址和接收方的IP地址。這時,對於這兩者,本機都不知道。於是,發出方的IP地址就設為0.0.0.0,接收方的IP地址設為255.255.255.255。

(3)最後的”UDP標頭”,設定發出方的埠和接收方的埠。這一部分是DHCP協議規定好的,發出方是68埠,接收方是67埠。

這個資料包構造完成後,就可以發出了。乙太網是廣播發送,同一個子網路的每臺計算機都收到了這個包。因為接收方的MAC地址是FF-FF-FF-FF-FF-FF,看不出是發給誰的,所以每臺收到這個包的計算機,還必須分析這個包的IP地址,才能確定是不是發給自己的。當看到發出方IP地址是0.0.0.0,接收方是255.255.255.255,於是DHCP伺服器知道”這個包是發給我的”,而其他計算機就可以丟棄這個包。

接下來,DHCP伺服器讀出這個包的資料內容,分配好IP地址,傳送回去一個”DHCP響應”資料包。這個響應包的結構也是類似的,乙太網標頭的MAC地址是雙方的網絡卡地址,IP標頭的IP地址是DHCP伺服器的IP地址(發出方)和255.255.255.255(接收方),UDP標頭的埠是67(發出方)和68(接收方),分配給請求端的IP地址和本網路的具體引數則包含在Data部分。

新加入的計算機收到這個響應包,於是就知道了自己的IP地址、子網掩碼、閘道器地址、DNS伺服器等等引數

網路通訊流程

本機獲取

  • 本機的IP地址:192.168.1.100
  • 子網掩碼:255.255.255.0
  • 閘道器的IP地址:192.168.1.1
  • DNS的IP地址:8.8.8.8

4.2 開啟瀏覽器,訪問

  想要訪問Google,在位址列輸入了網址:www.google.com。

dns協議(基於udp協議)

13臺根dns:

A.root-servers.net198.41.0.4美國
B.root-servers.net192.228.79.201美國(另支援IPv6
C.root-servers.net192.33.4.12法國
D.root-servers.net128.8.10.90美國
E.root-servers.net192.203.230.10美國
F.root-servers.net192.5.5.241美國(另支援IPv6
G.root-servers.net192.112.36.4美國
H.root-servers.net128.63.2.53美國(另支援IPv6
I.root-servers.net192.36.148.17瑞典
J.root-servers.net192.58.128.30美國
K.root-servers.net193.0.14.129英國(另支援IPv6)
L.root-servers.net198.32.64.12美國
M.root-servers.net202.12.27.33日本(另支援IPv6)

域名定義:http://jingyan.baidu.com/article/1974b289a649daf4b1f774cb.html

頂級域名:以.com,.net,.org,.cn等等屬於國際頂級域名,根據目前的國際網際網路域名體系,國際頂級域名分為兩類:類別頂級域名(gTLD)和地理頂級域名(ccTLD)兩種。類別頂級域名是         以"COM"、"NET"、"ORG"、"BIZ"、"INFO"等結尾的域名,均由國外公司負責管理。地理頂級域名是以國家或地區程式碼為結尾的域名,如"CN"代表中國,"UK"代表英國。地理頂級域名一般由各個國家或地區負責管理。

二級域名:二級域名是以頂級域名為基礎的地理域名,比喻中國的二級域有,.com.cn,.net.cn,.org.cn,.gd.cn等.子域名是其父域名的子域名,比喻父域名是abc.com,子域名就是www.abc.com或者.abc.com.
一般來說,二級域名是域名的一條記錄,比如alidiedie.com是一個域名,www.alidiedie.com是其中比較常用的記錄,一般預設是用這個,但是類似
.alidiedie.com的域名全部稱作是alidiedie.com的二級

Socket(套接字程式設計)

看socket之前,先來回顧一下五層通訊流程:

但實際上從傳輸層開始以及以下,都是作業系統幫咱們完成的,下面的各種包頭封裝的過程,用咱們去一個一個做麼?NO!

  Socket又稱為套接字,它是應用層與TCP/IP協議族通訊的中間軟體抽象層,它是一組介面。在設計模式中,Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket介面後面,對使用者來說,一組簡單的介面就是全部,讓Socket去組織資料,以符合指定的協議。當我們使用不同的協議進行通訊時就得使用不同的介面,還得處理不同協議的各種細節,這就增加了開發的難度,軟體也不易於擴充套件(就像我們開發一套公司管理系統一樣,報賬、會議預定、請假等功能不需要單獨寫系統,而是一個系統上多個功能介面,不需要知道每個功能如何去實現的)。於是UNIX BSD就發明了socket這種東西,socket遮蔽了各個協議的通訊細節,使得程式設計師無需關注協議本身,直接使用socket提供的介面來進行互聯的不同主機間的程序的通訊。這就好比作業系統給我們提供了使用底層硬體功能的系統呼叫,通過系統呼叫我們可以方便的使用磁碟(檔案操作),使用記憶體,而無需自己去進行磁碟讀寫,記憶體管理。socket其實也是一樣的東西,就是提供了tcp/ip協議的抽象,對外提供了一套介面,同過這個介面就可以統一、方便的使用tcp/ip協議的功能了。

  其實站在你的角度上看,socket就是一個模組。我們通過呼叫模組中已經實現的方法建立兩個程序之間的連線和通訊。也有人將socket說成ip+port,因為ip是用來標識網際網路中的一臺主機的位置,而port是用來標識這臺機器上的一個應用程式。 所以我們只要確立了ip和port就能找到一個應用程式,並且使用socket模組來與之通訊。

Socket又稱“套接字”,應用程式通常通過“套接字”向網路發出請求或者應答網路請求,使主機間或者一臺計算機的程序間可以通訊
類似於作業系統將複雜醜陋的控制計算機硬體的操作封裝成統一簡單的介面,只需要使用者學會如何作業系統就可以簡單快速的操作計算機硬體

套接字發展歷史及分類

套接字起源於 20 世紀 70 年代加利福尼亞大學伯克利分校版本的 Unix,即人們所說的 BSD Unix。 因此,有時人們也把套接字稱為“伯克利套接字”或“BSD 套接字”。一開始,套接字被設計用在同 一臺主機上多個應用程式之間的通訊。這也被稱程序間通訊,或 IPC。套接字有兩種(或者稱為有兩個種族),分別是基於檔案型的和基於網路型的。

基於檔案型別的套接字家族

套接字家族的名字:AF_UNIX

unix一切皆檔案,基於檔案的套接字呼叫的就是底層的檔案系統來取資料,兩個套接字程序執行在同一機器,可以通過訪問同一個檔案系統間接完成通訊

基於網路型別的套接字家族

套接字家族的名字:AF_INET

(還有AF_INET6被用於ipv6,還有一些其他的地址家族,不過,他們要麼是隻用於某個平臺,要麼就是已經被廢棄,或者是很少被使用,或者是根本沒有實現,所有地址家族中,AF_INET是使用最廣泛的一個,python支援很多種地址家族,但是由於我們只關心網路程式設計,所以大部分時候我麼只使用AF_INET)

TCP和UDP對比

TCP(Transmission Control Protocol)可靠的、面向連線的協議(eg:打電話)、傳輸效率低全雙工通訊(傳送快取&接收快取)、面向位元組流。使用TCP的應用:Web瀏覽器;檔案傳輸程式。

UDP(User Datagram Protocol)不可靠的、無連線的服務,傳輸效率高(傳送前時延小),一對一、一對多、多對一、多對多、面向報文(資料包),盡最大努力服務,無擁塞控制。使用UDP的應用:域名系統 (DNS);視訊流;IP語音(VoIP)。

TCP協議下的socket

個生活中的場景。你要打電話給一個朋友,先撥號,朋友聽到電話鈴聲後提起電話,這時你和你的朋友就建立起了連線,就可以講話了。等交流結束,結束通話電話結束此次交談。 生活中的場景就解釋了這工作原理。

  先從伺服器端說起。伺服器端先初始化Socket,然後與埠繫結(bind),對埠進行監聽(listen),呼叫accept阻塞,等待客戶端連線。在這時如果有個客戶端初始化一個Socket,然後連線伺服器(connect),如果連線成功,這時客戶端與伺服器端的連線就建立了。客戶端傳送資料請求,伺服器端接收請求並處理請求,然後把迴應資料傳送給客戶端,客戶端讀取資料,最後關閉連線,一次互動結束

TCP服務端
package main

import (
	"fmt"
	"net"
)

func main()  {
	// 監聽
	listener,err := net.Listen("tcp","127.0.0.1:8000")
	if err != nil{
		fmt.Println("err =",err)
		return
	}
	defer listener.Close()
	// 阻塞等待使用者連結
	conn,err := listener.Accept()
	if err != nil {
		fmt.Println("err =",err)
		return
	}

	// 接受使用者的請求
	buf := make([]byte,1024) // 緩衝區大小1024
	conn.Read(buf)
	n , err1 := conn.Read(buf)
	if err1 != nil {
		fmt.Println("err1=",err1)
		return
	}
	fmt.Println("buf=",string(buf[:n]))
	defer conn.Close()
}

// 可以使用nc代替客戶端發信息
TCP客戶端
package main

import (
	"fmt"
	"net"
)

func main()  {
	// 自動連結伺服器
	conn,err := net.Dial("tcp","127.0.0.1:8000")
	if err != nil{
		fmt.Println("err:=",err)
		return
	}
	defer conn.Close()

	// 傳送資料
	conn.Write([]byte("youmen"))
}
接受多個使用者服務端
// Server.go
package main

import (
	"fmt"
	"net"
	"strings"
)

func main()  {
	// 監聽
	listener,err := net.Listen("tcp","127.0.0.1:8000")
	if err != nil{
		fmt.Println("err =",err)
		return
	}
	defer listener.Close()
	// 阻塞等待使用者連結
	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("err =", err)
			return
		}

		// 處理使用者請求,新建一個協程
		go HandleConn(conn)
	}
}

// 處理使用者請求
func HandleConn(conn net.Conn){
	// 函式呼叫自動關閉
	defer conn.Close()

	// 獲取客戶端的網路地址資訊
	addr := conn.RemoteAddr().String()
	fmt.Println(addr,"add connect success")

	buf := make([]byte,2048)

	for {
		// 讀取使用者資料
		n, err := conn.Read(buf)
		if err != nil {
			fmt.Println("err = ", err)
			return
		}
		fmt.Printf("[%s]: %s\n",addr, string(buf[:n]))

		if "exit" == string(buf[:n-1]){
			fmt.Println(addr,"exit")
			return
		}
		// 將資料轉換為大寫,再給使用者資料
		conn.Write([]byte(strings.ToUpper(string(buf[:n]))))
	}
}

// client.go