客戶端/服務端架構python
七層模型,亦稱OSI(Open System Interconnection)參考模型,是參考模型是國際標準化組織(ISO)制定的一個用於計算機或通訊系統間互聯的標準體系。它是一個七層的、抽象的模型體,不只包括一系列抽象的術語或概念,也包括具體的協議。面試
分層:編程
網絡服務與最終用戶的一個接口。緩存
協議有:HTTP FTP TFTP SMTP SNMP DNS TELNET HTTPS POP3 DHCP安全
數據的表示、安全、壓縮。(在五層模型裏面已經合併到了應用層)服務器
格式有,JPEG、ASCll、DECOIC、加密格式等網絡
創建、管理、終止會話。(在五層模型裏面已經合併到了應用層)session
對應主機進程,指本地主機與遠程主機正在進行的會話架構
定義傳輸數據的協議端口號,以及流控和差錯校驗。app
協議有:TCP UDP,數據包一旦離開網卡即進入網絡傳輸層
進行邏輯地址尋址,實現不一樣網絡之間的路徑選擇。
協議有:ICMP IGMP IP(IPV4 IPV6) ARP RARP
創建邏輯鏈接、進行硬件地址尋址、差錯校驗等功能。(由底層網絡定義協議)
將比特組合成字節進而組合成幀,用MAC地址訪問介質,錯誤發現但不能糾正。
創建、維護、斷開物理鏈接。(由底層網絡定義協議)
相對於SOCKET開發者,TCP建立過程和連接折除過程是由TCP/IP協議棧自動建立的.所以開發者並不須要控制這個過程.可是對於理解TCP底層運做機制,至關有幫助.
並且對於有網絡協議工程師之類筆試,幾乎是必考的內容.企業對這個問題熱情之高,出乎個人意料:-)。有時上午面試前強調這個問題,並重復講一次,下午幾乎每個人都被問到這個問題。
所以在這裏詳細解釋一下這兩個過程。
所謂三次握手(Three-way Handshake),是指創建一個TCP鏈接時,須要客戶端和服務器總共發送3個包。
三次握手的目的是鏈接服務器指定端口,創建TCP鏈接,並同步鏈接雙方的序列號和確認號並交換 TCP 窗口大小信息.在socket編程中,客戶端執行connect()時。將觸發三次握手。
第一次握手:
客戶端發送一個TCP的SYN標誌位置1的包指明客戶打算鏈接的服務器的端口,以及初始序號X,保存在包頭的序列號(Sequence Number)字段裏。
第二次握手:
服務器發回確認包(ACK)應答。即SYN標誌位和ACK標誌位均爲1同時,將確認序號(Acknowledgement Number)設置爲客戶的I S N加1以.即X+1。
第三次握手.
客戶端再次發送確認包(ACK) SYN標誌位爲0,ACK標誌位爲1.而且把服務器發來ACK的序號字段+1,放在肯定字段中發送給對方.而且在數據段放寫ISN的+1
TCP的鏈接的拆除須要發送四個包,所以稱爲四次揮手(four-way handshake)。客戶端或服務器都可主動發起揮手動做,在socket編程中,任何一方執行close()操做便可產生揮手操做。
(1)第一次揮手:Client發送一個FIN,用來關閉Client到Server的數據傳送,Client進入FIN_WAIT_1狀態。 (2)第二次揮手:Server收到FIN後,發送一個ACK給Client,確認序號爲收到序號+1(與SYN相同,一個FIN佔用一個序號),Server進入CLOSE_WAIT狀態。 (3)第三次揮手:Server發送一個FIN,用來關閉Server到Client的數據傳送,Server進入LAST_ACK狀態。 (4)第四次揮手:Client收到FIN後,Client進入TIME_WAIT狀態,接着發送一個ACK給Server,確認序號爲收到序號+1,Server進入CLOSED狀態,完成四次揮手。
socket一般也稱做"套接字",用於描述IP地址和端口,是一個通訊鏈的句柄,應用程序一般經過"套接字"向網絡發出請求或者應答網絡請求。套接字能惟一表示出互聯網上一臺主機上的一個應用程序
socket起源於Unix,而Unix/Linux基本哲學之一就是「一切皆文件」,對於文件用【打開】【讀寫】【關閉】模式來操做。socket就是該模式的一個實現,socket便是一種特殊的文件,一些socket函數就是對其進行的操做(讀/寫IO、打開、關閉)
socket和file的區別:
file模塊是針對某個指定文件進行【打開】【讀寫】【關閉】
socket模塊是針對 服務器端 和 客戶端Socket 進行【打開】【讀寫】【關閉】
#server端 import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) phone.bind(('127.0.0.1',8000)) #綁定手機卡 phone.listen(5) print('---------') while True: conn,addr=phone.accept() #等電話 print("電話線路是",conn) print("客戶端的手機號是",addr) while True: #通信循環 try: msg=conn.recv(1024) #收消息 if not msg:break print('客戶端發來的消息是:',msg) conn.send(msg.upper())#發消息 except Exception: break conn.close() phone.close()
#客戶端 #!/usr/bin/env python #-*- coding:utf-8 -*- import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(('127.0.0.1',8000)) while True: msg=input(">>>:").strip() if not msg: continue phone.send(msg.encode('utf-8')) #發送給服務端的消息 data=phone.recv(1024) print('收到服務端發來的消息',data) phone.close()
## socket參數使用 參數一:地址簇 socket.AF_INET IPv4(默認) socket.AF_INET6 IPv6 socket.AF_UNIX 只可以用於單一的Unix系統進程間通訊 參數二:類型 socket.SOCK_STREAM 流式socket , for TCP (默認) socket.SOCK_DGRAM 數據報式socket , for UDP socket.SOCK_RAW 原始套接字,普通的套接字沒法處理ICMP、IGMP等網絡報文,而SOCK_RAW能夠;其次,SOCK_RAW也能夠處理特殊的IPv4報文;此外,利用原始套接字,能夠經過IP_HDRINCL套接字選項由用戶構造IP頭。 socket.SOCK_RDM 是一種可靠的UDP形式,即保證交付數據報但不保證順序。SOCK_RAM用來提供對原始協議的低級訪問,在須要執行某些特殊操做時使用,如發送ICMP報文。SOCK_RAM一般僅限於高級用戶或管理員運行的程序使用。 socket.SOCK_SEQPACKET 可靠的連續數據包服務 參數三:協議 0 (默認)與特定的地址家族相關的協議,若是是 0 ,則系統就會根據地址格式和套接類別,自動選擇一個合適的協議
服務端套接字函數 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() 建立一個與該套接字相關的文件