一. 傳輸層算法
在上述三層協議中咱們,ip協議幫咱們定位到子網絡. mac地址幫咱們定位到一臺計算機,並與其通信,編程
但本質上,計算機的通信是爲了應用程序可以通信,而一臺計算機上不可能運行一個應用程序設計模式
問題:緩存
就像咱們同時運行QQ軟件和微信軟件, 當計算機收到一個數據包時, 須要知道這個數據包究竟是給服務器
哪一個應用程序的.微信
解決方案:網絡
爲每個應用程序綁定一個端口號, 端口號就是一個數字, 取值範圍爲 0 -- 65536 其中 0 -- 1023是socket
系統保留的tcp
再次捋清思路:函數
端口定位應用程序, ip 定位網絡, mac 定位計算機
能夠經過這三個地址,找到全世界計算機中惟一的一個應用程序, 使咱們編寫網絡應用程序成爲可能.
傳輸層協議 :
爲何要有傳輸層協議 ?
應用程序可相互傳遞數據了, 還記得在ip協議中有一個路由算法麼? 會自動選擇最佳的傳輸路徑,
將致使你的數據包可能走了不一樣的路線, 形成接受順序錯亂, 以及發生丟包等, 爲了保證數據傳輸的
完整性, 誕生了傳輸層協議!
TCP :基於連接傳輸數據, 可保證數據傳輸的完整性
優勢 :經過三次握手來與服務器創建鏈接
能夠保證數據的完整性.
a機器給b機器發送數據包, 要求b機器必須當即返回一個確認包,
a機器會等待一段時間,若是超時尚未收到確認, 則重發數據.
缺點:
傳輸效率低.
使用場景 : 文字聊天. 支付寶轉帳等,
UDP : 不須要創建鏈接,直接發送
缺點:
不能保證數據的完整性
優勢:
傳輸效率比TCP高不少
使用場景 : 視頻通話,語音通話, 遊戲等.
socket 是什麼?
Socket是應用層與TCP/IP協議族通訊的中間軟件抽象層,它是一組接口。在設計模式中,
Socket其實就是一個門面模式,它把複雜的TCP/IP協議族隱藏在Socket接口後面,對用戶來講,
一組簡單的接口就是所有,讓Socket去組織數據,以符合指定的協議。
因此,咱們無需深刻理解tcp/udp協議,socket已經爲咱們封裝好了,咱們只須要遵循socket的
規定去編程,寫出的程序天然就是遵循tcp/udp標準的。
使用 socket:
在使用socket的時候用戶須要關心的是, ip地址, port端口. 傳輸協議TCP/UDP,你要發送的數據data
在寫網絡編程的時候,必然是兩臺代碼, 對應着客戶端和服務器.
socket 的工做流程 :
一個生活中的場景。你要打電話給一個朋友,先撥號,朋友聽到電話鈴聲後提起電話,
這時你和你的朋友就創建起了鏈接,就能夠講話了。等交流結束,掛斷電話結束這次交談。
生活中的場景就解釋了這工做原理。
先從服務器端提及。服務器端先初始化Socket,而後與端口綁定(bind),對端口進行監聽(listen),
調用accept阻塞,等待客戶端鏈接。在這時若是有個客戶端初始化一個Socket,而後鏈接服務器
(connect),若是鏈接成功,這時客戶端與服務器端的鏈接就創建了。客戶端發送數據請求,
服務器端接收請求並處理請求,而後把迴應數據發送給客戶端,客戶端讀取數據,最後關閉
鏈接,一次交互結束
服務端套接字函數
s.bind() 綁定(主機,端口號)到套接字
s.listen() 開始TCP監聽
s.accept() 被動接受TCP客戶的鏈接,(阻塞式)等待鏈接的到來
客戶端套接字函數
s.connect() 主動初始化TCP服務器鏈接
s.connect_ex() connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常
公共用途的套接字函數
s.recv() 接收TCP數據
s.send() 發送TCP數據(send在待發送數據量大於己端緩存區剩餘空間時,數據丟失,不會發完)
s.sendall() 發送完整的TCP數據(本質就是循環調用send,sendall在待發送數據量大於己端緩存區剩餘空間時,數據不丟失,循環調用send直到發完)
s.recvfrom() 接收UDP數據
s.sendto() 發送UDP數據
s.getpeername() 鏈接到當前套接字的遠端的地址
s.getsockname() 當前套接字的地址
s.getsockopt() 返回指定套接字的參數
s.setsockopt() 設置指定套接字的參數
s.close() 關閉套接字
面向鎖的套接字方法
s.setblocking() 設置套接字的阻塞與非阻塞模式
s.settimeout() 設置阻塞套接字操做的超時時間
s.gettimeout() 獲得阻塞套接字操做的超時時間
面向文件的套接字的函數
s.fileno() 套接字的文件描述符
s.makefile() 建立一個與該套接字相關的文件
使用socket來完成TCP通信
應該先完成服務器的代碼編寫
TCP 服務器 :
import socket
# 1. 先建立一個表明服務器的socket對象
s = socket.socket()
# 2. 綁定ip地址與 端口號
# 127.0.0.1 表示當前電腦的ip
address = ('127.0.0.1',8090) #傳入ip與端口
s.bind((address))
print ('服務器已啓動')
# 3. 開始監聽這個端口
# 參數5 表示能夠有五個處於半鏈接狀態的鏈接.(不是控制最大鏈接數的參數.)
s.listen(5)
# 4. 接受鏈接請求
# 該函數是阻塞的. 會卡主程序的執行,必須等到有一個客戶端進來纔會繼續執行.
它會返回一個元組, 第一個表明客戶端的socket對象, 第二個是客戶端的端口
client,c_address = s.accept()
print('有一個鏈接已創建')
# 5.讀寫數據
# 接受數據 , 參數1024是須要接受的字節數
res = client.recv(1024)
print(res)
# 6. 關閉鏈接
s.close() (通常不會關閉服務器.都是關閉客戶端)
TCP 客戶端:
import socket
# 1. 建立客戶端的socket對象
c = socket.socket()
# 2. 鏈接到服務器
server_address = ('127.0.0.1',8080) # 端口必須跟服務器同樣
# 3.創建鏈接
c.connect(server_address)
# 4.讀寫數據
# 發送數據到服務器
c.send('hello 我是客戶端')
# 5. 關閉鏈接
c.close()
使用socket來完成UDP通信,同樣是先建立服務端
UDP 服務端:
import socket
# 1.建立socket對象
# 必須本身定義參數
s = socket.socket(type = socket.SOCK_DGRAM)
# 2. 綁定端口和ip
s.bind(('127.0.0.1',10000))
# 3. 接受數據. 接受數據的時候,沒有客戶端來鏈接,也會卡主,等待客戶端來鏈接了.再正常運行程序
res = s.recv(1024)
print(res)
# 4.
UDP 客戶端 :
import socket
# 1. 建立客戶端
c = socket.socket(type = socket.SOCK_DGRAM)
# 不須要鏈接, 能夠直接發送數據,只須要知道對方的ip和端口便可.
c.sendto('這是UDP的客戶端'.encode('utf-8'),(127.0.0.1,10000))
# 關閉客戶端
c.close()