1、TCP簡介數據庫
6、tcp長鏈接和短鏈接socket
7、TCP/IP協議tcp
TCP介紹函數
TCP協議,傳輸控制協議(英語:Transmission Control Protocol,縮寫爲 TCP)是一種面向鏈接的、可靠的、基於字節流的傳輸層通訊協議,由IETF的RFC 793定義。學習
TCP通訊須要通過建立鏈接、數據傳送、終止鏈接三個步驟。
TCP通訊模型中,在通訊開始以前,必定要先創建相關的連接,才能發送數據,相似於生活中,"打電話"。
TCP特色
1. 面向鏈接
通訊雙方必須先創建鏈接才能進行數據的傳輸,雙方都必須爲該鏈接分配必要的系統內核資源,以管理鏈接的狀態和鏈接上的傳輸。
雙方間的數據傳輸均可以經過這一個鏈接進行。
完成數據交換後,雙方必須斷開此鏈接,以釋放系統資源。
這種鏈接是一對一的,所以TCP不適用於廣播的應用程序,基於廣播的應用程序請使用UDP協議。
2. 可靠傳輸
1)TCP採用發送應答機制
TCP發送的每一個報文段都必須獲得接收方的應答才認爲這個TCP報文段傳輸成功
2)超時重傳
發送端發出一個報文段以後就啓動定時器,若是在定時時間內沒有收到應答就從新發送這個報文段。
TCP爲了保證不發生丟包,就給每一個包一個序號,同時序號也保證了傳送到接收端實體的包的按序接收。而後接收端實體對已成功收到的包發回一個相應的確認(ACK);若是發送端實體在合理的往返時延(RTT)內未收到確認,那麼對應的數據包就被假設爲已丟失將會被進行重傳。
3)錯誤校驗
TCP用一個校驗和函數來檢驗數據是否有錯誤;在發送和接收時都要計算校驗和。
4) 流量控制和阻塞管理
流量控制用來避免主機發送得過快而使接收方來不及徹底收下。
TCP與UDP的不一樣點
面向鏈接(確認有建立三方交握,鏈接已建立才做傳輸。)
有序數據傳輸
重發丟失的數據包
捨棄重複的數據包
無差錯的數據傳輸
阻塞/流量控制
udp通訊模型
udp通訊模型中,在通訊開始以前,不須要創建相關的連接,只須要發送數據便可,相似於生活中,"寫信""
TCP通訊模型
udp通訊模型中,在通訊開始以前,必定要先創建相關的連接,才能發送數據,相似於生活中,"打電話""
2、tcp網絡程序-客戶端
tcp客戶端
tcp客戶端,並非像以前一個段子:一個顧客去飯館吃飯,這個顧客要點菜,就問服務員我們飯店有客戶端麼,而後這個服務員很是客氣的說道:先生 咱們飯店不用客戶端,咱們直接送到您的餐桌上
若是,不學習網絡的知識是否是 說不定也會發生那樣的笑話 ,哈哈
所謂的服務器端:就是提供服務的一方,而客戶端,就是須要被服務的一方
tcp客戶端構建流程
tcp的客戶端要比服務器端簡單不少,若是說服務器端是須要本身買手機、查手機卡、設置鈴聲、等待別人打電話流程的話,那麼客戶端就只須要找一個電話亭,拿起電話撥打便可,流程要少不少
示例代碼:
from socket import * # 建立套接字 tcp_client_socket = socket(AD_INET, SOCK_STREAM) # 目的地址 server_ip = input("服務端ip:") server_port = input("服務端端口:") # 連接服務器 tcp_client_socket.connect((server_ip, int(server_port))) # 客戶端發送信息 send_data = input("輸入發送的信息:") tcp_client_socket.send(send_data.encode('utf-8')) # 接受服務端發來的信息 recv_data = tcp_client_socket.recv(1024) print("收到的信息:%s" % recv_data.decode('utf-8')) # 關閉套接字 tcp_client_socket.close()
3、tcp網絡程序-服務器
tcp服務器
生活中的電話機
若是想讓別人能更夠打通我們的電話獲取相應服務的話,須要作如下幾件事情:
買個手機
插上手機卡
設計手機爲正常接聽狀態(即可以響鈴)
靜靜的等着別人撥打
tcp服務器
如同上面的電話機過程同樣,在程序中,若是想要完成一個tcp服務器的功能,須要的流程以下:
socket建立一個套接字
bind綁定ip和port
listen使套接字變爲能夠被動連接
accept等待客戶端的連接
recv/send接收發送數據
一個很簡單的tcp服務器以下:
from socket import * # 建立套接字 tcp_server_socket = socket(AF_INET, SOCK_STREAM) # 綁定地址 tcp_server_socket.bind(('192.168.1.1', 8001)) # 使用socket建立的套接字默認的屬性是主動的,使用listen將其變爲被動的,這樣就 能夠接收別人的連接了 tcp_server_socket.listen(128) # 若是有新的客戶端來連接服務器,那麼就產生一個新的套接字專門爲這個客戶端服務 # client_socket用來爲這個客戶端服務 # tcp_server_socket就能夠省下來專門等待其餘新客戶端的連接 client_socket, client_addr = tcp_server_socket.accept() # 接受對方發來的消息 recv_data = client_socket.recv(1024) print("收到的消息:%s" % recv_data.decode('utf-8')) # 回覆對方消息 send_data = input("回覆消息:") client_socket.send(send_data.encode('utf-8')) # 關閉爲這個客戶端服務的套接字,只要關閉了,就意味着爲不能再爲這個客戶端服務 了,若是還須要服務,只能再次從新鏈接 client_socket.close() # 關閉服務器的套接字 tcp_server_socket.close()
tcp注意點
tcp服務器通常狀況下都須要綁定,不然客戶端找不到這個服務器
tcp客戶端通常不綁定,由於是主動連接服務器,因此只要肯定好服務器的ip、port等信息就好,本地客戶端能夠隨機
tcp服務器中經過listen能夠將socket建立出來的主動套接字變爲被動的,這是作tcp服務器時必需要作的
當客戶端須要連接服務器時,就須要使用connect進行連接,udp是不須要連接的而是直接發送,可是tcp必須先連接,只有連接成功才能通訊
當一個tcp客戶端鏈接服務器時,服務器端會有1個新的套接字,這個套接字用來標記這個客戶端,單獨爲這個客戶端服務
listen後的套接字是被動套接字,用來接收新的客戶端的連接請求的,而accept返回的新套接字是標記這個新客戶端的
關閉listen後的套接字意味着被動套接字關閉了,會致使新的客戶端不可以連接服務器,可是以前已經連接成功的客戶端正常通訊。
關閉accept返回的套接字意味着這個客戶端已經服務完畢
當客戶端的套接字調用close後,服務器端會recv解堵塞,而且返回的長度爲0,所以服務器能夠經過返回數據的長度來區別客戶端是否已經下線
4、案例:文件下載器
服務器參考代碼以下:
from socket import * def get_file(file_name): try: with open(file_name, 'rb') as f: content = f.read() return content except: print("%s文件不存在" % file_name) def main(): # 建立套接字 tcp_server_socket = socket(AF_INET, SOCK_STREAM) # 綁定地址 tcp_server_socket.bind(("192.168.1.1", 8002)) # 將主動套接字變爲被動套接字 tcp_server_socket.listen(128) while True: # 等待客戶端鏈接 client_socket, client_addr = tcp_server_socket.accept() # 接受客戶端發來的數據 recv_data = client_socket.recv(1024) file_name = recv_data.decode("utf-8") print("對方請求下載的文件:%s" % file_name) file_content = get_file(file_name) # 發送文件的數據給客戶端 # 由於獲取打開文件時是以rb方式打開,因此file_content中的數據已是二 進制的格式,所以不須要encode編碼 if file_content: client_socket.send(file_content) else: client_socket.send("請求的文件不存在".encode('utf-8')) # 關閉這個套接字 client_socket.close() # 關閉服務器 tcp_server_socket.close() if __name__ == '__main__': main()
客戶端 參考代碼以下:
from socket import * # 建立套接字 tcp_client_socket = socket(AF_INET, SOCK_STREAM) # 目的地址 server_ip = input("服務器ip:") server_port = input("服務器port:") # 鏈接服務器 tcp_client_socket.connect((server_ip, int(server_port))) # 發送下載的文件名 file_name = input("下載的文件名:") tcp_client_socket.send(file_name.encode('utf-8')) # 接受文件 file_content = tcp_client_socket.recv(1024) # 驗證文件是否存在,存在就建立文件 if file_content.decode('utf-8') == "請求的文件不存在": print("請求的文件不存在") else: with open("new_"+file_name, 'wb') as f: f.write(file_content) print("文件下載成功") # 關閉套接字 tcp_client_socket.close()
5、tcp三次握手、四次揮手
tcp三次握手
tcp四次揮手
6、tcp長鏈接和短鏈接
TCP在真正的讀寫操做以前,server與client之間必須創建一個鏈接,
當讀寫操做完成後,雙方再也不須要這個鏈接時它們能夠釋放這個鏈接,
鏈接的創建經過三次握手,釋放則須要四次握手,
因此說每一個鏈接的創建都是須要資源消耗和時間消耗的。
TCP通訊的整個過程,以下圖:
1. TCP短鏈接
模擬一種TCP短鏈接的狀況:
client 向 server 發起鏈接請求
server 接到請求,雙方創建鏈接
client 向 server 發送消息
server 迴應 client
一次讀寫完成,此時雙方任何一個均可以發起 close 操做
在步驟5中,通常都是 client 先發起 close 操做。固然也不排除有特殊的狀況。
從上面的描述看,短鏈接通常只會在 client/server 間傳遞一次讀寫操做!
2. TCP長鏈接
再模擬一種長鏈接的狀況:
client 向 server 發起鏈接
server 接到請求,雙方創建鏈接
client 向 server 發送消息
server 迴應 client
一次讀寫完成,鏈接不關閉
後續讀寫操做...
長時間操做以後client發起關閉請求
3. TCP長/短鏈接操做過程
3.1 短鏈接的操做步驟是:
創建鏈接——數據傳輸——關閉鏈接...創建鏈接——數據傳輸——關閉鏈接
3.2 長鏈接的操做步驟是:
創建鏈接——數據傳輸...(保持鏈接)...數據傳輸——關閉鏈接
4. TCP長/短鏈接的優勢和缺點
長鏈接能夠省去較多的TCP創建和關閉的操做,減小浪費,節約時間。
對於頻繁請求資源的客戶來講,較適用長鏈接。
client與server之間的鏈接若是一直不關閉的話,會存在一個問題,
隨着客戶端鏈接愈來愈多,server遲早有扛不住的時候,這時候server端須要採起一些策略,
如關閉一些長時間沒有讀寫事件發生的鏈接,這樣能夠避免一些惡意鏈接致使server端服務受損;
若是條件再容許就能夠以客戶端機器爲顆粒度,限制每一個客戶端的最大長鏈接數,
這樣能夠徹底避免某個蛋疼的客戶端連累後端服務。
5. TCP長/短鏈接的應用場景
長鏈接多用於操做頻繁,點對點的通信,並且鏈接數不能太多狀況。
每一個TCP鏈接都須要三次握手,這須要時間,若是每一個操做都是先鏈接,
再操做的話那麼處理速度會下降不少,因此每一個操做完後都不斷開,
再次處理時直接發送數據包就OK了,不用創建TCP鏈接。
例如:數據庫的鏈接用長鏈接,若是用短鏈接頻繁的通訊會形成socket錯誤,
並且頻繁的socket 建立也是對資源的浪費。
而像WEB網站的http服務通常都用短連接,由於長鏈接對於服務端來講會耗費必定的資源,
而像WEB網站這麼頻繁的成千上萬甚至上億客戶端的鏈接用短鏈接會更省一些資源,
若是用長鏈接,並且同時有成千上萬的用戶,若是每一個用戶都佔用一個鏈接的話,
那可想而知吧。因此併發量大,但每一個用戶無需頻繁操做狀況下需用短連好。
7、TCP/IP協議(族)
早期的計算機網絡,都是由各廠商本身規定一套協議,IBM、Apple和Microsoft都有各自的網絡協議,互不兼容
爲了把全世界的全部不一樣類型的計算機都鏈接起來,就必須規定一套全球通用的協議,爲了實現互聯網這個目標,互聯網協議族(Internet Protocol Suite)就是通用協議標準。
由於互聯網協議包含了上百種協議標準,可是最重要的兩個協議是TCP和IP協議,因此,你們把互聯網的協議簡稱TCP/IP協議(族)
經常使用的網絡協議以下圖所示:
說明:
網際層也稱爲:網絡層
網絡接口層也稱爲:鏈路層
另一套標準