專業理解: socket是應用層與TCP/IP協議族通訊的中間軟件抽象層,它是一組接口,Socket其實就是使用一個門面模式(門面模式要求一個子系統的外部與其內部的通訊必須經過一個統一的門面(Facade)對象進行。門面模式提供一個高層次的接口,使得子系統更易於使用), 它把複雜的TCP/IP協議族隱藏在Socket接口後面,對用戶來講,一組簡單的接口就是所有.讓socket去組織數據.python
簡易理解:socket就是一個模塊,封裝了網絡通訊所須要的全部東西.經過調用socket模塊實現兩個進程之間的鏈接和通信.(也可稱爲:IP+Port , IP用於表示互聯網中的一臺主機的位置,而port則是定位到這個機器上的某個程序.)shell
套接字起源於 20 世紀 70 年代加利福尼亞大學伯克利分校版本的 Unix,即人們所說的 BSD Unix。 所以,有時人們也把套接字稱爲「伯克利套接字」或「BSD 套接字」。一開始,套接字被設計用在同 一臺主機上多個應用程序之間的通信。這也被稱進程間通信,或 IPC。套接字有兩種(或者稱爲有兩個種族),分別是基於文件型的和基於網絡型的。編程
兩個種族:緩存
1.基於網絡類型的套接字:AF_INET服務器
(還有AF_INET6被用於ipv6,還有一些其餘的地址家族,不過,他們要麼是隻用於某個平臺,要麼就是已經被廢棄,或者是不多被使用,或者是根本沒有實現,全部地址家族中,AF_INET是使用最普遍的一個,python支持不少種地址家族,可是因爲咱們只關心網絡編程,因此大部分時候我麼只使用AF_INET)網絡
2.基於文件類型的套接字:AF_UNIXsocket
unix一切皆文件,基於文件的套接字調用的就是底層的文件系統來取數據,兩個套接字進程運行在同一機器,能夠經過訪問同一個文件系統間接完成通訊tcp
import socket socket.socket(socket_family,socket_type,protocal=0) #socket_family 地址簇 : 能夠是 AF_UNIX 或 AF_INET。 #socket_type : 能夠是 SOCK_STREAM 或 SOCK_DGRAM。 # protocol : 通常不填,默認值爲 0。 ### 獲取tcp/ip套接字 # socket.AF_INET: IPV4 IP協議 # socket.SOCK_STREAM : 提供面向鏈接的穩定數據傳輸 TCP是流傳輸 tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ### 獲取udp/ip套接字 # socket.AF_INET: IPV4 IP協議 # socket.SOCK_DGRAM 使用不連續不可靠的數據包鏈接 , 數據包 udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
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() 建立一個與該套接字相關的文件
tcp是基於連接的,必須先啓動服務端,而後再啓動客戶端去連接服務端
### Client 客戶端 import socket client=socket.socket() # 建立 socket對象 client.connect(('127.0.0.1',8848)) # 鏈接服務端地址,端口號8848 # 發送數據 client.send('abcd'.encode('utf-8')) # 客戶端 發送字節類型數據 from_server_data=client.recv(1024) # 客戶端接收服務端響應的數據 print(from_server_data) client.close() # 關閉客戶端鏈接
### server服務端 import socket server=socket.socket() # 1 . 建立 socket的server對象 server.bind(('127.0.0.1',8848)) # 2 . 綁定IP 和端口 # 3. 監聽 server.listen(5) # 4. 接受鏈接 conn,addr=server.accept() # 程序等待 print(conn,addr) # 打印 conn 鏈接信息 ,和addr地址信息 data=conn.recv(1024) # 接收客戶端發送的數據 最多接收1024字節 conn.send(data.upper()) # 發送給客戶端數據 conn.close() # 關閉鏈接 server.close() #關閉服務
### client import socket client=socket.socket() client.connect(('127.0.0.1',8848))# 鏈接 # 發送數據 while 1: user_input=input('>>').strip().encode('utf-8') # 用戶輸入的字符串數據,轉換成字節格式 client.send(user_input) # 客戶端 發送字節數據 from_server_data=client.recv(1024) # 接收服務端 返回的數據 ,每次接收1024字節 print(f'來自服務端的信息:{from_server_data.decode("utf8")}') client.close()
### server服務端 import socket server=socket.socket() # 1 . 建立 server對象 server.bind(('127.0.0.1',8848)) # 2 . 綁定IP 和端口 # 3. 監聽 server.listen(5) # 4. 接受鏈接 conn,addr=server.accept() # 程序等待 print(conn,addr) while 1 : # 循環去 data=conn.recv(1024) # 接收數據 最多接收1024字節 print(f'來自客戶端{addr}的信息{data.decode("utf-8")}') to_client=input('>>>').strip().encode('utf-8') conn.send(to_client) # 發送數據 conn.close() # 關閉鏈接 server.close() #關閉服務
### 客戶端 client , # 啓動多個客戶端, 依次排隊, 當第一個鏈接斷開時,第二個鏈接就會鏈接服務端 import socket client =socket.socket() client.connect(('127.0.0.1',9999)) while 1: try: user_input=input('請輸入信息:>>>').strip().encode('utf-8') if user_input.upper()==b'Q': client.send(user_input) break client.send(user_input) ser_data=client.recv(1024) print(f'來自服務端的信息:{ser_data.decode("utf-8")}') except ConnectionResetError: break client.close()
### server 服務端 import socket server=socket.socket() server.bind(('127.0.0.1',9999)) server.listen(2) while 1: conn,addr=server.accept() print(conn,addr) while 1: try: cli_data=conn.recv(1024) print(f'來自客戶端:{addr}消息: {cli_data.decode("utf-8")}') if cli_data.upper()==b'Q': break response=input('回覆消息:>>').strip().encode('utf-8') conn.send(response) except ConnectionResetError: break conn.close() # 當上一個conn 鏈接已經關閉或斷開時,進入下一次循環,等待新的鏈接 server.close()
# -*-coding:utf-8-*- import subprocess while 1: user_input=input('請輸入指令:').strip() obj=subprocess.Popen(user_input, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) if obj.stdout: print(f'正確信息: {obj.stdout.read().decode("gbk")}') else: print(f'錯誤信息: {obj.stderr.read().decode("gbk")}')
什麼是粘包:
客戶端不能一次性接收完服務器返回的信息.這些沒有接收完的信息會保存在一個緩衝區內. 等下次鏈接再來時,先把上一次沒有收完的數據給接收了.
### server import socket import subprocess server =socket.socket() server.bind(('127.0.0.1',8877)) server.listen(5) while 1: conn , addr=server.accept() print(conn,addr) while 1: try: cmd=conn.recv(1024) # 接收客戶端發來的cmd 字節指令 print(cmd) # 執行本機cmd命令 obj=subprocess.Popen(cmd.decode('utf-8'), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # 拼接返回信息 msg_right=obj.stdout.read() msg_err=obj.stderr.read() result=(msg_right+msg_err).decode('gbk').encode('utf-8') print(result.decode('utf-8')) # 向客戶端發送結果 conn.send(result) except ConnectionResetError: break conn.close() server.close()
### client import socket client=socket.socket() #鏈接服務器 client.connect(('127.0.0.1',8877)) while 1: user_input=input('請輸入指令:>>>').strip() # 發送指令 以字節形式 client.send(user_input.encode('utf-8')) # 接收返回結果 try: ser_data=client.recv(1024) print(ser_data.decode('utf-8')) except UnicodeDecodeError as e: print(e) client.close()