python學習筆記11,python學習筆記
網路編程網路編程需要知道的概念
網路體繫結構就是使用這些用不同媒介串連起來的不同裝置和網路系統在不同的應用環境下實現互通性,並滿足各種業務需求的一種粘合劑。網路體繫結構解決互質性問題彩是分層方法。
1.網路(OSI)的7層模型:
應用程式層--->為應用程式提供網路通訊服務
展示層--->資料表示
會話層--->主機間通訊(兩個應用進程間)
傳輸層--->端到端的串連,隔離網路的上下層協議,使得網路應用與下層協議無關
網路層--->尋找最優路徑,轉寄資料包
資料連結層--->無差錯的鏈路串連
物理層--->二進位傳輸
2.連接埠
是一種抽象的軟體結構,包括一些資料結構和I/O緩衝區。與協議有關。
3.通訊端存在於通訊地區中。
通訊地區也叫地址族,它是一個抽象的概念,主要用於將通過通訊端通訊的進程的共有特性綜合在一起。
為保證資料的正確性,在網路通訊協定中需要制定網路位元組順序,採用統一的網路位元組順序。
網路通訊三要素:
IP地址:用於表示主機(IP地址 = 網路ID+主機ID)
連接埠號碼:用於標識進程的邏輯連接埠
傳輸協議:TCP UDP
網路通訊過程就是一個不斷封裝和解析的過程
Socket是串連應用程式與網路驅動程式的橋樑,Socket在應用程式中建立,通過綁定操作與驅動程式建立關係。
通訊端
通訊端是為特定網路通訊協定(例如TCP/IP,ICMP/IP,UDP/IP等)套件對上的網路應用程式提供者提供當前可移植標準的對象。它們允許程式接受並進行串連,如發送和接受資料。為了建立通訊通道,網路通訊的每個端點擁有一個通訊端對象極為重要。
通訊端為BSD UNIX系統核心的一部分,而且他們也被許多其他類似UNIX的作業系統包括Linux所採納。許多非BSD UNIX系統(如ms-dos,windows,os/2,mac os及大部分主機環境)都以庫形式提供對通訊端的支援。
三種最流行的通訊端類型是:stream,datagram和raw。stream和datagram通訊端可以直接與TCP協議進行介面,而raw通訊端則介面到IP協議。但通訊端並不限於TCP/IP。
通訊端模組 -------
SOCKET()模組
通訊端模組是一個非常簡單的基於對象的介面,它提供對低層BSD通訊端樣式網路的訪問。使用該模組可以實現客戶機和伺服器通訊端。要在python 中建立具有TCP和流通訊端的簡單伺服器,需要使用socket模組。利用該模組包含的函數和類定義,可產生通過網路通訊的程式。
SOCKET內建方法
| 函數 |
描述 |
| 伺服器端通訊端函數 |
|
| s.bind() |
綁定地址(主機,連接埠號碼對)到通訊端 s.bind(address) 將通訊端綁定到地址。 address地址的格式取決於地址族。在AF_INET下,以元組(host,port)的形式表示地址。 |
| s.listen() |
開始TCP 監聽 開始監聽傳入串連。添加參數是指定在拒絕串連之前,可以掛起的最大串連數量。 如果參數等於5,表示核心已經接到了串連請求,但伺服器還沒有調用accept進行處理的串連個數最大為5 這個值不能無限大,因為要在核心中維護串連隊列 |
| s.accept() |
被動接受TCP 客戶的串連,(阻塞式)等待串連的到來 接受串連並返回(conn,address),其中conn是新的通訊端對象,可以用來接收和發送資料。address是串連用戶端的地址。 接收TCP 客戶的串連(阻塞式)等待串連的到來 |
| 用戶端通訊端函數 |
|
| s.connect() |
主動初始化TCP 伺服器串連,參數為地址(address) 串連到address處的通訊端。一般,address的格式為元組(hostname,port),如果串連出錯,返回socket.error錯誤。 |
| s.connect_ex() |
connect()函數的擴充版本,出錯時返回出錯碼,而不是拋異常 同上,只不過會有傳回值,串連成功時返回 0 ,串連失敗時候返回編碼,例如:10061 |
| 公用用途的通訊端函數 |
|
| s.recv() |
接收TCP 資料 sk.recv(bufsize[,flag]) 接受通訊端的資料。資料以字串形式返回,bufsize指定最多可以接收的數量。flag提供有關訊息的其他資訊,通常可以忽略。 |
| s.send() |
發送TCP 資料 將string中的資料發送到串連的通訊端。傳回值是要發送的位元組數量,該數量可能小於string的位元組大小。即:可能未將指定內容全部發送。 |
| s.sendall() |
完整發送TCP 資料 將string中的資料發送到串連的通訊端,但在返回之前會嘗試發送所有資料。成功返回None,失敗則拋出異常。 內部通過遞迴調用send,將所有內容發送出去。 |
| s.recvfrom() |
接收UDP 資料 與recv()類似,但傳回值是(data,address)。其中data是包含接收資料的字串,address是發送資料的通訊端地址。 |
| s.sendto() |
發送UDP 資料 將資料發送到通訊端,address是形式為(ipaddr,port)的元組,指定遠程地址。傳回值是發送的位元組數。該函數主要用於UDP協議。 |
| s.getpeername() |
串連到當前通訊端的遠端的地址 返回串連通訊端的遠程地址。傳回值通常是元組(ipaddr,port)。 |
| s.getsockname() |
當前通訊端的地址 返回通訊端自己的地址。通常是一個元組(ipaddr,port) |
| s.getsockopt() |
返回指定通訊端的參數 |
| s.setsockopt() |
設定指定通訊端的參數 |
| s.close() |
關閉通訊端 |
| 面向模組的通訊端函數 |
|
| s.setblocking() |
設定通訊端的阻塞與非阻塞模式 是否阻塞(預設True),如果設定False,那麼accept和recv時一旦無資料,則報錯。 |
| s.settimeout()a |
設定阻塞通訊端操作的逾時時間 設定通訊端操作的逾時期,timeout是一個浮點數,單位是秒。值為None表示沒有逾時期。一般,逾時期應該在剛建立通訊端時設定,因為它們可能用於串連的操作(如 client 串連最多等待5s ) |
| s.gettimeout()a |
得到阻塞通訊端操作的逾時時間 |
| 面向檔案的通訊端的函數 |
|
| s.fileno() |
通訊端的檔案描述符 |
| s.makefile() |
建立一個與該通訊端關連的檔案 |
| |
|
建立伺服器串連需要六個步驟:
1.建立socket對象。調用socket建構函式。
socket=socket.socket(familly,type)
family的值可以是AF_UNIX(Unix域,用於同一台機器上的進程間通訊),也可以是AF_INET(對於IPV4協議的TCP和 UDP),至於type參數,SOCK_STREAM(流通訊端)或者 SOCK_DGRAM(資料報文通訊端),SOCK_RAW(raw通訊端)。
2.則是將socket綁定(指派)到指定地址上,socket.bind(address)
address必須是一個雙元素元組,((host,port)),主機名稱或者ip地址+連接埠號碼。如果連接埠號碼正在被使用或者保留,或者主機名稱或ip地址錯誤,則引發socke.error異常。
3.綁定後,必須準備好通訊端,以便接受串連請求。
socket.listen(backlog)
backlog指定了最多串連數,至少為1,接到串連請求後,這些請求必須排隊,如果隊列已滿,則拒絕請求。
4.伺服器通訊端通過socket的accept方法等待客戶請求一個串連:
connection,address=socket.accept()
調用accept方法時,socket會進入'waiting'(或阻塞)狀態。客戶請求串連時,方法建立串連並返回伺服器。accept方法返回 一個含有倆個元素的元組,形如(connection,address)。第一個元素(connection)是新的socket對象,伺服器通過它與客 戶通訊;第二個元素(address)是客戶的internet地址。
5. 處理階段,伺服器和客戶通過send和recv方法通訊(傳輸資料)。伺服器調用send,並採用字串形式向客戶發送資訊。send方法 返回已發送的字元個數。伺服器使用recv方法從客戶接受資訊。調用recv時,必須指定一個整數來控制本次調用所接受的最大資料量。recv方法在接受 資料時會進入'blocket'狀態,最後返回一個字串,用它來表示收到的資料。如果發送的量超過recv所允許,資料會被截斷。多餘的資料將緩衝於接 受端。以後調用recv時,多餘的資料會從緩衝區刪除。
6. 傳輸結束,伺服器調用socket的close方法以關閉串連。
建立一個簡單客戶串連則需要4個步驟。
第1步,建立一個socket以串連伺服器 socket=socket.socket(family,type)
第2步,使用socket的connect方法串連伺服器 socket.connect((host,port))
第3步,客戶和伺服器通過send和recv方法通訊。
第4步,結束後,客戶通過調用socket的close方法來關閉串連。
以下案例都是以TCP方式串連
import socketsk = socket.socket()address = ('127.0.0.1',8000)sk.bind(address) sk.listen(2)print("......")while True: conn, addr = sk.accept() print(addr) while True: try: date = conn.recv(1024) except Exception: break if not date:break print(str(date, "utf8")) inp = input(">>>>:") conn.send(bytes(inp,"utf8"))# conn, addr = sk.accept()# while True:# date = conn.recv(1024)# if not date:# conn, addr = sk.accept()# continue# print(str(date, "utf8"))# inp = input(">>>>:")# conn.send(bytes(inp,"utf8"))# conn.close()conn.close()服務端import socketsk = socket.socket()address = ("127.0.0.1",8000)sk.connect(address)while True: inp = input(">>>>:") if inp == "q": break sk.send(bytes(inp, "utf8")) date = sk.recv(1024) print(str(date,"utf8"))sk.close()用戶端
簡單的類比qq對話(socket模組)
import socket,subprocesssk = socket.socket()address = ('0.0.0.0',8000)sk.bind(address)sk.listen(2)print("......")while True: conn, addr = sk.accept() print(addr) while True: try: date = conn.recv(1024) except Exception: break if not date:break print(str(date, "utf8")) obj = subprocess.Popen(str(date, "utf8"),shell=True,stdout=subprocess.PIPE) cmd_result = obj.stdout.read() result_len = str(len(cmd_result)) print(result_len) conn.send(bytes(result_len,"utf8")) conn.send(cmd_result) conn.close()serverimport socketsk = socket.socket()address = ("127.0.0.1",8000)sk.connect(address)while True: inp = input(">>>>:") if inp == "q": break sk.send(bytes(inp, "utf8")) result_len = int(str(sk.recv(1024),"utf8")) print(result_len) date = bytes() while len(date) != result_len: da = sk.recv(1024) date+=da print(str(date,"gbk"))sk.close()client
簡單的FTP上傳圖片
import subprocessimport socketimport ossk=socket.socket()print(sk)address=('127.0.0.1',8000)sk.bind(address)sk.listen(3)print('waiting......')BASE_DIR=os.path.dirname(os.path.abspath(__file__))while 1: conn, addr = sk.accept() while 1: data=conn.recv(1024) cmd,filename,filesize=str(data,'utf8').split('|') path=os.path.join(BASE_DIR,'tupian',filename) filesize=int(filesize) f=open(path,'ab') has_receive=0 while has_receive!=filesize: data=conn.recv(1024) f.write(data) has_receive+=len(data) f.close()serverimport socketimport ossk=socket.socket()address=('127.0.0.1',8000)sk.connect(address)BASE_DIR=os.path.dirname(os.path.abspath(__file__))while True: inp=input('>>>').strip()# post|11.png cmd,path=inp.split('|') path=os.path.join(BASE_DIR,path) filename=os.path.basename(path) file_size=os.stat(path).st_size file_info='post|%s|%s'%(filename,file_size) sk.sendall(bytes(file_info,'utf8')) f=open(path,'rb') has_sent=0 while has_sent!=file_size: data=f.read(1024) sk.sendall(data) has_sent+=len(data) f.close() print('上傳成功')client