網絡編程知識點剖析前端
一. C/S 架構: Client / Server 客戶端 / 服務端算法
B/S 架構: Browser / Server 前端 / 服務端shell
二.網絡編程通訊流程.編程
網卡 mac地址 IP地址 子網掩碼 網關 DNS服務器 (進行域名(domain name)和與之相對應的IP地址 (IP address)轉換的服務器。) json
DHCP (自動分配IP) NAT (Network Address Translation,網絡地址轉換) 端口 路由器服務器
交換機 集線器 廣播 單播 廣播風暴 arp協議(地址解析協議) 路由協議網絡
三.網絡通訊協議架構
1. osi七層: tcp\ ip 五層:dom
應用層 應用層 socket
表示層 傳輸層
會話層 網路層
傳輸層 數據鏈路層
網絡層 物理層
數據鏈路層
物理層
2. TCP\IP 協議存在 傳輸層
Tcp : 面向鏈接,消息可靠,效率相對差,面向流的消息格式,無消息保護邊界
Udp : 面向無鏈接,消息不可靠,效率高,面向包的消息格式,有消息保護邊界
tcp三次握手:1.(client) > [SYN包 ]->(server) 請求創建鏈接
2.(client) < [SYN/ACK] < (server) severs收到syn 發送[SYN/ACK]確認包
3.(client)> [ACK] >(server) client收到[SYN/ACK] 在發一個[ACK]確認包
tcp四次揮手:1.(client) > [ACK/FIN] >(server) 發送包 請求關閉
2.(client) < [ACK] <(server) 收到包 贊成關閉
3.(client) <[ACK/FIN] <(server) 收到包 是否收到 贊成關閉 消息
4.(client) > [ACK/FIN] >(server) 發送包 收到過程2的消息,
四.socket
1. 服務端與客戶端 手法消息 基本結構
server>>>>>>>>>>>>>>>>> import socket sk = socket.socket() sk.bind(('127.0.0.1',8898)) #把地址綁定到套接字 sk.listen() #監聽連接 conn,addr = sk.accept() #接受客戶端連接 ret = conn.recv(1024) #接收客戶端信息 print(ret) #打印客戶端信息 conn.send(b'hi') #向客戶端發送信息 conn.close() #關閉客戶端套接字 sk.close() #關閉服務器套接字(可選) client>>>>>>>>>>>>>>>> import socket sk = socket.socket() # 建立客戶套接字 sk.connect(('127.0.0.1',8898)) # 嘗試鏈接服務器 sk.send(b'hello!') ret = sk.recv(1024) # 對話(發送/接收) print(ret) sk.close() # 關閉客戶套接字
server>>>>>>>>>>>>>>>>>>>>>>>> import socket udp_sk = socket.socket(type=socket.SOCK_DGRAM) #建立一個服務器的套接字 udp_sk.bind(('127.0.0.1',9000)) #綁定服務器套接字 msg,addr = udp_sk.recvfrom(1024) print(msg) udp_sk.sendto(b'hi',addr) # 對話(接收與發送) udp_sk.close() # 關閉服務器套接字 client>>>>>>>>>>>>>>>>>>>>>>>> import socket ip_port=('127.0.0.1',9000) udp_sk=socket.socket(type=socket.SOCK_DGRAM) udp_sk.sendto(b'hello',ip_port) back_msg,addr=udp_sk.recvfrom(1024) print(back_msg.decode('utf-8'),addr)
2.緩衝區
做用: 提升效率,將發送或者接受信息的過程與網絡傳輸隔離開,解耦
特性: 1.I/O緩衝區在每一個TCP套接字中單獨存在;
2.I/O緩衝區在建立套接字時自動生成;
3.即便關閉套接字也會繼續傳送輸出緩衝區中遺留的數據;
4.關閉套接字將丟失輸入緩衝區中的數據。
大小: 通常默認爲 8K, 能夠經過 getsockopt() 函數獲取
3.粘包
TCP會粘包、UDP永遠不會粘包
粘包的兩種現象:
1.連續發送小包而且間隔時間很短,就會發送兩個消息合併在一塊兒的狀況,被一次接受了,(Nagel 優化算法致使的, 避免連續發送小包,影響傳輸xiaol)
2.一次發送數據過大,對方一次未接受完致使下次接受的時候,連同第一次剩下的消息,一同接受了,致使粘包.
解決粘包的方案:
緣由是由於雙方不知道對方發送的消息長度
1.發送消息以前先發送消息的長度,而後收到對方的確認信息後再發送消息.
2.經過struct模塊,自定義包頭,將消息長度打包成4個字節長度的信息,連同你要發送的數據,一塊兒發送過去
打包:pack('i',長度) 長度是個整數
解包:unpack('i',接受的那4個字節),獲得的是元祖
Sendall(): 循環的send直到數據發送完畢.
Socketsserver(): 實現tcp協議下,一個服務端能夠同時和多個客戶端進行通訊.
import socket,struct,json import subprocess phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) phone.bind(('127.0.0.1',8080)) phone.listen(5) while True: conn,addr=phone.accept() while True: cmd=conn.recv(1024) if not cmd:break print('cmd: %s' %cmd) res=subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) err=res.stderr.read() print(err) if err: back_msg=err else: back_msg=res.stdout.read() headers={'data_size':len(back_msg)} head_json=json.dumps(headers) head_json_bytes=bytes(head_json,encoding='utf-8') conn.send(struct.pack('i',len(head_json_bytes))) #先發報頭的長度 conn.send(head_json_bytes) #再發報頭 conn.sendall(back_msg) #在發真實的內容 conn.close()
import socket import struct,json client= socket.socket() client.connect(("127.0.0.1",8080)) while True: cmd=input(">>: ") if not cmd:continue client.send(bytes(cmd,encoding='utf-8')) head=client.recv(4) head_json_len=struct.unpack('i',head)[0] head_json=json.loads(client.recv(head_json_len).decode('utf-8')) data_len=head_json['data_size'] recv_size=0 recv_data=b'' while recv_size < data_len: recv_data = client.recv(1024) + recv_data recv_size = len(recv_data) + recv_size print(recv_data.decode('gbk'))
import socketserver class Myserver(socketserver.BaseRequestHandler): def handle(self): self.data = self.request.recv(1024).strip() print("{} wrote:".format(self.client_address[0])) print(self.data) self.request.sendall(self.data.upper()) if __name__ == "__main__": HOST, PORT = "127.0.0.1", 9999 # 設置allow_reuse_address容許服務器重用地址 socketserver.TCPServer.allow_reuse_address = True # 建立一個server, 將服務地址綁定到127.0.0.1:9999 #server = socketserver.TCPServer((HOST, PORT),Myserver) server = socketserver.ThreadingTCPServer((HOST, PORT),Myserver) # 讓server永遠運行下去,除非強制中止程序 server.serve_forever()
import socket HOST, PORT = "127.0.0.1", 9999 data = "hello" # 建立一個socket連接,SOCK_STREAM表明使用TCP協議 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: sock.connect((HOST, PORT)) # 連接到客戶端 sock.sendall(bytes(data + "\n", "utf-8")) # 向服務端發送數據 received = str(sock.recv(1024), "utf-8")# 從服務端接收數據 print("Sent: {}".format(data)) print("Received: {}".format(received))