C/S和B/S架構python
C : client S : server 客戶端,服務端shell
B : browser S : server 瀏覽器,服務端編程
B/S架構本質也是C/S瀏覽器
網絡的七層協議:(應表會傳網數物)服務器
物理層:電信號(0和1)網絡
數據鏈路層:把物理層的電信號分組,每一組叫一個數據報或數據幀,每一幀有:報頭head和數據data兩部分。多線程
頭固定18字節:6:發送者地址/6:接收者地址/6:數據類型架構
網絡層:ssh
ip:ipv4:32位2進製表示:點分十進制表示異步
子網掩碼:經過子網掩碼和ip判斷兩個ip是否處於同一個網段,經過ip地址和子網掩碼作按位與運算
ip地址: 172.16.10.1: 10101100.00010000.00001010.000000001
子網掩碼:255.255.255.0: 11111111.11111111.11111111.000000000
按位與運算:172.16.10.0 10101100.00010000.00001010.000000000
ip和mac有轉換關係:主要是由於ARP協議和mac地址學習。
傳輸層:
tcp協議:
udp協議:
直接發送,不須要響應,因此數據不可靠。(看視頻花屏)
端口:
會話層:使應用創建和維持會話,並能使會話得到同步。
表示層:做用之一是爲異種機通訊提供一種公共語言,以便能進行互操做。
應用層:應用層嚮應用程序提供服務,這些服務按其嚮應用程序提供的特性分紅組,並稱爲服務元素。
模塊 | 描述 |
---|---|
socket | 基於傳輸層TCP、UDP協議進行網絡編程的模塊 |
asyncore | socket模塊的異步版,支持基於傳輸層協議的異步通訊 |
asynchat | asyncore的加強版 |
cgi | 基本的CGI(Common Gateway Interface,早期開發動態網站的技術)支持 |
E-mail 和 MIME消息處理模塊 | |
ftplib | 支持FTP協議的客戶端模塊 |
httplib、http.client | 支持HTTP協議以及HTTP客戶端模塊 |
imaplib | 支持IMAP4協議的客戶端模塊 |
mailbox | 操做不一樣格式郵箱的模塊 |
mailcap | 支持Mailcap文件處理的模塊 |
nntplib | 支持NTTP協議的客戶端模塊 |
smtplib | 支持SMTP協議(發送郵件)的客戶端模塊 |
poplib | 支持POP3協議的客戶端模塊 |
telnetlib | 支持TELNET協議的客戶端模塊 |
urllib | 支持URL處理的模塊 |
xmlrpc | 支持XML-RPC協議的服務器和客戶端模塊 |
接下來咱們會主要討論socket模塊
程序再使用socket以前,必須先建立socket對象,能夠經過如下語法建立socket實例:
s = socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
那麼創好socket對象後就須要區分服務端和客戶端了。
做爲服務器端使用的socket必須綁定到指定IP地址和端口,並在該IP地址和端口進行監聽,接收來自客戶端的鏈接。
socket對象提供了以下經常使用方法:
服務端:
import socket host = socket.gethostname() # 獲取本機host server = socket.socket() server.bind((host,8080)) server.listen(5) while 1: c, addr = server.accept() # 與客戶端創建鏈接 c.send(b"start:") while 1: '''通訊循環,try爲了等待客戶端斷開後鏈接其餘的客戶端''' try: print(f"\t\033[1;36m{c.recv(1024).decode()}\033[0m") msg = input(">>").encode('utf-8') c.send(msg) except Exception: print("客戶端斷開鏈接了!") break
客戶端:
import socket host = socket.gethostname() # 獲取本機host cilent = socket.socket() cilent.connect((host, 8080)) while 1: '''通信循環''' print(f"\t\033[1;36m{cilent.recv(1024).decode()}\033[0m") msg = input(">>").encode('utf-8') cilent.send(msg)
TCP協議中的數據都是以數據流(type=SOCK_STREAM)的形式傳遞的,很容易發生幾回send的數據被一次recv(接收),或者被截成了好幾段。爲了解決粘包問題,咱們借用了數據報的思想,給每一條數據加一個固定長度的頭。這裏引入struct
模塊來建立固定的頭。
示例:寫一個仿SHH的客戶端和服務端
服務端
import socket import subprocess import struct server = socket.socket() host = socket.gethostname() port = 8081 server.bind((host, port)) server.listen(5) while 1: c, addr = server.accept() print(addr, "鏈接了 >>>") msg = b"hello " le = struct.pack('i',len(msg)) # 將要發送的數據的長度封裝成固定長度爲4的二進制數據 c.send(le) # 先發送一個頭 c.send(msg) # 再發送數據 try: while 1: ssh = c.recv(1024) obj = subprocess.Popen(ssh.decode('gbk'), shell=True, stdout=subprocess.PIPE , stderr=subprocess.PIPE) # subprocess是與系統交互的模塊 msg = obj.stdout.read() or obj.stderr.read() # 必然拿到其中一項 le = struct.pack('i',len(msg)) # 將結果打上頭 c.send(le) # 與上同樣 c.send(msg) except Exception: print(" 斷開鏈接 !")
客戶端
import socket import struct client = socket.socket() host = socket.gethostname() port = 8081 client.connect((host,port)) while 1: le = struct.unpack('i', client.recv(4))[0] # 解析頭,獲取數據長度 print(client.recv(le).decode('gbk')) # shell只接收gbk編碼 ssh = input(" 請輸入命令 >>") client.send(ssh.encode('gbk')) # 返回執行結果
socketserver模塊實現了多線程通訊。使用socketserver建立服務端:
#使用socketserver寫服務端 import socketserver #本身定義一個類,必須繼承StreamRequestHandler或BaseRequestHandler class MyTcp(socketserver.StreamRequestHandler): #必須重寫handle方法 def handle(self): '''這是服務端與客戶端交互的方法''' try: while True : #通訊循環 # print(self) #給客戶端回消息 #conn對象就是request #接收數據 print(self.client_address) data=self.request.recv(1024) print(data) if len(data)==0: return #發送數據 self.request.send(data.upper()) except Exception: pass if __name__ == '__main__': #實例化獲得一個tcp鏈接的對象,Threading意思是說,只要來了請求,它自動的開線程來處理鏈接跟交互數據 #第一個參數是綁定的地址,第二個參數傳一個類 server=socketserver.ThreadingTCPServer(('127.0.0.1',8009),MyTcp) #一直在監聽 #這麼理解:只要來一個請求,就起一個線程交互 server.serve_forever()