在本地電腦上有兩個python文件 regist.py 、login.py 一個註冊,一個登陸。這兩個python一個是寫用戶信息,一個是讀用戶信息,要怎麼作呢?python
經過以前的知識,咱們能夠經過 regist.py 序列化一個數據並持久保存到磁盤上,而後 login.py 在取讀取這個文件就行。web
可是,當這兩個文件在不一樣的主機上時,咱們就須要經過網絡編程來實現,相似qq、網盤、微信。shell
在這七層中,咱們應該明確:編程
每層運行經常使用物理設備:設計模式
每層運行常見的協議瀏覽器
要記牢:ip是在網絡層,tcp、udp等協議是在傳輸層。服務器
理解 socket微信
從表現形式來說,socket就是 ip:port,從設計模式來說,socket其實就是一個門面模式,它把複雜的tcp/ip協議族隱藏在socket接口後面,對用戶來講,一組簡單的接口就是所有,讓socket去組織數據,以符合指定的協議。網絡
從python的角度來看,socket就是一個模塊,咱們經過調用模塊中已經實現的方法創建兩個進程之間的鏈接和通訊。socket = ip:port ip 用來標識互聯網中的一臺主機的位置,而port是用來標識這臺主機上的一個應用程序,因此咱們只要確立了ip和port就能找到一個應用程序,而且使用socket模塊來與之通訊。socket
tcp( Transmission Control Protocol ): 可靠的、面向鏈接的協議、傳輸效率低全雙工通訊、面向字節流。使用tcp應用:web瀏覽器;電子郵件、文件傳輸程序。
udp( User Datagram Protocol ): 不可靠的、無鏈接的服務,傳輸效率高,一對1、一對多、多對1、多對多、面向報文,盡最大努力服務,無擁塞控制。
使用udp的應用:域名系統;視頻流;ip語音
1. 基於tcp協議的socket
tcp是基於連接的,必須先啓動服務端,而後再啓動客戶端去鏈接服務端
sever端
import socket sock = socket.socket() # 建立 socket 對象 sock.bind(('127.0.0.1', 8080)) # 綁定ip和port sock.listen(5) # 創建監聽連接 conn, addr = sock.accept() # 阻塞,隨時準備接收客戶端連接 res = conn.recv(1024) # 阻塞,等待接收客戶端發送過來的數據 conn.send(b'hello client.') # 向客戶端發送信息 conn.close() # 關閉本次連接 sock.close() # 關閉服務器socket
client端
import socket sock = socket.socket() # 建立 socket 對象 sock.connect(('127.0.0.1', 8080)) # 去鏈接服務端的socket sock.send(b'hello server.') # 發送信息給服務端的socket res = sock.recv(1024) # 接收服務端socket發送過來的信息 print(res) sock.close() # 關閉客戶端鏈接
總結:
server端:
(1)建立socket對象
(2)綁定ip:port, 這裏 ip爲str類型,port爲int類型
(3)創建socket監聽
(4)準備接收客戶端鏈接並返回socket鏈接信息和addr信息
(5)conn.send 發送信息、 conn.recv 接收消息
(6)先關閉鏈接,再關閉 socket
client端:
(1)建立socket對象
(2)經過 connect 嘗試去鏈接服務端的socket
(3)sock.send 發送消息、sock.recv 接收消息
(4)關閉鏈接的socket
2. 基於UDP協議的socket
udp是無連接的,啓動服務以後能夠直接接受消息,不須要提早創建連接
server端
import socket udp_sk = socket.socket(type=socket.SOCK_DGRAM) # 建立一個服務器的套接字,這裏必需要定義 type=socket.SOCK_DGRAM udp_sk.bind(('127.0.0.1', 8080)) # 綁定服務器套接字 msg, addr = udp_sk.recvfrom(1024) # udp服務器端第一次通訊必須是接收信息 print(msg) udp_sk.sendto(b'hello, client.', addr) # 發送信息 udp_sk.close() # 關閉服務器套接字
client端
import socket ip_port = ('127.0.0.1', 8080) # 創建ip、port元組 udp_sk = socket.socket(type=socket.SOCK_DGRAM) # 建立一個服務器的套接字,這裏必需要定義 type=socket.SOCK_DGRAM udp_sk.sendto(b'hello server.', ip_port) # 發送消息給服務器端,在udp中第一次交互由客戶端發起 back_msg, addr = udp_sk.recvfrom(1024) # 接收數據包括(服務器端數據,套接字信息) print(back_msg) udp_sk.close() # 關閉套接字
練習:使用 socket 模塊實現 服務端 和 客戶端 鏈接並執行命令。
import socket import subprocess sk_server = socket.socket() # 建立 socket對象 sk_server.bind(('localhost', 8080)) # 創建socket sk_server.listen(5) # 開啓監聽 conn, addr = sk_server.accept() # 接收客戶端信息 while True: command = conn.recv(1024).decode() cmd_res = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) # 執行命令 stdout = cmd_res.stdout.read() stderr = cmd_res.stderr.read() result = stdout if stdout else stderr res_size = len(result) # 統計命令執行結果大小 print(res_size) conn.sendall(str(res_size).encode()) # 首先發送命令結果大小 response = conn.recv(1024).decode() conn.sendall(result) # 發送命令結果
import socket sk_client = socket.socket() sk_client.connect(('localhost', 8080)) while True: cmd = input('>>>').strip() if not cmd: continue sk_client.sendall(cmd.encode()) res_size = int(sk_client.recv(1024).decode()) # 接收命令結果大小 sk_client.sendall(b'000') revice_size = 0 while res_size != revice_size: # 經過命令大小循環獲取數據 data = sk_client.recv(1024) revice_size += len(data) print(data.decode('gbk'))