詳解python的網(wǎng)絡(luò)編程基礎(chǔ)
一.什么是網(wǎng)絡(luò)編程
網(wǎng)絡(luò)編程涉及到一些計算機基礎(chǔ)知識,還跟你的電腦系統(tǒng)有關(guān),mac os/Linux和windows是不同的,由于我用的是windows,所以以下所有都是windows操作系統(tǒng)的適用的,并且里面的字符編碼windows和mac os也是不同的,這里我們實現(xiàn)的只是簡單的服務(wù)端發(fā)送什么,客戶端就接收到什么,之后還會有模擬ssh的遠程命令還有粘包問題,最后也可以實現(xiàn)文件的下載。
網(wǎng)絡(luò)編程還涉及到重要的一部分理論知識包括什么是網(wǎng)絡(luò)還有比較重要的五層協(xié)議,以我的理解,這些東西就是專業(yè)的告訴你,在你的電腦上假設(shè)要接收一些文件,這些東西是怎么傳輸過來的,你的電腦又是怎么接收的,所以這里無非就是你的電腦即客戶端和傳輸文件的一方即服務(wù)點進行的一個交互,這些我都建議你去聽一下(我感覺以個人能力講這些會有點水平不足)但是大的方面都離不開一種交互。
二.socket
眾所周知,python功能的強大很大一方面就在于它有強大的第三方外部庫,socket這個庫又叫套接字,專業(yè)解釋就是應(yīng)用程序通常通過"套接字"向網(wǎng)絡(luò)發(fā)出請求或者應(yīng)答網(wǎng)絡(luò)請求,使主機間或者一臺計算機上的進程間可以通訊,進而通過socket這個庫就可以實現(xiàn)我在前面所說的客戶端和服務(wù)端的交互。
1.socket的基本語法
socket(family,type,[protocol])
其中的family有三種
socket.AF_UNIX
只能夠用于單一的Unix系統(tǒng)進程間通信
socket.AF_INET
服務(wù)器之間網(wǎng)絡(luò)通信
socket.AF_INET6 IPv6
type也有三種
socket.SOCK_STREAM
流式socket , 當(dāng)使用TCP時選擇此參數(shù)
socket.SOCK_DGRAM
數(shù)據(jù)報式socket ,當(dāng)使用UDP時選擇此參數(shù)
socket.SOCK_RAW
原始套接字,普通的套接字無法處理ICMP、IGMP等網(wǎng)絡(luò)報文,而SOCK_RAW
可以;其次,SOCK_RAW也可以處理特殊的IPv4報文;此外,利用原始套接字,可以通過IP_HDRINCL套接字選項由用戶構(gòu)造IP頭。
而protocol 指明所要接收的協(xié)議類型,通常為0或者不填,基本上是不寫的
2.與socket有關(guān)的一些函數(shù)
服務(wù)端函數(shù)
address
一般指你的電腦上的ip地址,即你打開Windows的命令提示符,你聯(lián)網(wǎng)之后輸入ipconfig命令,里面的IPV4
s.bind(address)
將套接字綁定到地址,即在客戶端中,你要把你的程序綁定一個ip和端口才能實現(xiàn)交互
s.listen(backlog)
操作系統(tǒng)可以掛起的最大連接數(shù)量。即你的服務(wù)端最多能把數(shù)據(jù)傳給幾個客戶端
s.accept()
接受TCP連接并返回(conn,address),其中conn是新的套接字對象,可以用來接收和發(fā)送數(shù)據(jù)。address是連接客戶端的地址。
客戶端函數(shù)
s.connect(address)
連接到客戶端address處的套接字
s.recv(bufsize)
接受TCP套接字的數(shù)據(jù)。數(shù)據(jù)以字符串形式返回,bufsize指定要接收的最大數(shù)據(jù)量。
公共函數(shù)
s.send(string)
發(fā)送TCP數(shù)據(jù)。將string中的數(shù)據(jù)發(fā)送到連接的套接字。返回值是要發(fā)送的字節(jié)數(shù)量,該數(shù)量可能小于string的字節(jié)大小。
s.sendall(string)
完整發(fā)送TCP數(shù)據(jù)。將string中的數(shù)據(jù)發(fā)送到連接的套接字,但在返回之前會嘗試發(fā)送所有數(shù)據(jù)。成功返回None,失敗則拋出異常。
s.recvfrom(bufsize)
接受UDP套接字的數(shù)據(jù)。與recv()類似,但返回值是(data,address)。其中data是包含接收數(shù)據(jù)的字符串,address是發(fā)送數(shù)據(jù)的套接字地址。
s.sendto(string,address)
發(fā)送UDP數(shù)據(jù)。將數(shù)據(jù)發(fā)送到套接字,address是形式為(ipaddr,port)的元組,指定遠程地址。返回值是發(fā)送的字節(jié)數(shù)。
s.close()
關(guān)閉套接字。
三.程序需求
既然是實現(xiàn)一種交互,那么生活中打電話和接收電話也可以理解為一種交互,打電話就可以理解為發(fā)送數(shù)據(jù),收電話就可以理解為接收數(shù)據(jù),這樣就有了服務(wù)端和客戶端,這里我們以這樣一種場景實現(xiàn)交互。
服務(wù)端分析
如果你要發(fā)送數(shù)據(jù)首先你得有一個手機然后引入socket進行交互,然后你要進行一系列的綁定操作即你需要上面的函數(shù)來實現(xiàn),首先你在客戶端模擬一個手機引入socket之后,你需要進行綁定,開機,等待電話鏈接,收發(fā)消息,掛電話等功能
注意:
1.在綁定操作過程中,你需要聯(lián)網(wǎng)之后輸入你本機的ip地址,即你打開命令提示符你輸入ipconifg命令的IPV4地址
2.在綁定你的地址后后面會加一個端口號,這個端口號是任意的,不過有時候會被占用,被占用則更改以下就好
3.在手法消息中還有一個upper函數(shù),是將客戶端發(fā)送過來的數(shù)據(jù)以大寫的形式在發(fā)送給客戶端
4.在客戶端用accept是接受TCP連接并返回(conn,address)
--------------------------------服務(wù)端---------------------- import socket #1.買手機 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # print(phone) #測試你的手機 #2.插卡 綁定手機卡 phone.bind(("192.168.2.18",3234)) #3.開機 phone.listen(5) #5代表最大掛起的連接數(shù) #4.等電話鏈接 print("starting") conn,client_add = phone.accept() # 5.收發(fā)消息 data=conn.recv(1024) #1024代表接收數(shù)據(jù)的最大數(shù),單位是bits print("客戶端數(shù)據(jù)",data) conn.send(data.upper()) #6.掛電話 conn.close() #7.關(guān)機 phone.close()
客戶端分析
服務(wù)端分析完,客戶端和服務(wù)端是一一對應(yīng)的,在收發(fā)消息這里,客戶端給服務(wù)端發(fā)送一個小寫的hello,服務(wù)端就又會給客戶端回一個大寫的HELLO
-------------------------------客戶端----------------------------- import socket #1.買手機 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # print(phone) #2.撥號 phone.connect(("192.168.2.18",3234)) #3.發(fā)收消息 phone.send("hells".encode("utf")) data=phone.recv(1024) print(data) phone.close()
四.代碼升級
加上通信循環(huán)
上面的代碼我們可以看出,我們實現(xiàn)的太簡單了,我們只是固定的讓它收發(fā)消息,我們?nèi)绾巫屵@個程序在客戶端和服務(wù)端之間循環(huán)并且收發(fā)你想要的東西呢,這是我們加入輸入和循環(huán)就可以
----------------------------服務(wù)端------------------------ import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # print(phone) phone.bind(("172.20.10.4",3234)) phone.listen(5) print("starting") conn,client_add = phone.accept() print(client_add) while True: data=conn.recv(1024) print("客戶端數(shù)據(jù)",data) conn.send(data.upper()) conn.close() phone.close()
----------------------------------客戶端------------------------ import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # print(phone) phone.connect(("172.20.10.4",3234)) while True: msg = input(">>>:").strip() phone.send(msg.encode("utf-8")) data=phone.recv(1024) print(data) phone.close()
大家可以看到,我們只是在客戶端里面加入了循環(huán)輸入功能如何在服務(wù)端里加入循環(huán),這樣就可以實現(xiàn)一種循環(huán)輸入
加上連接循環(huán)以及完善
我們以上的程序都是一個客戶端對應(yīng)一個服務(wù)端,但是真正應(yīng)該服務(wù)端可以對應(yīng)多個客戶端收發(fā)數(shù)據(jù)。我們主要修改的是服務(wù)端代碼,客戶端代碼應(yīng)該是變化不大的,除了客戶端應(yīng)該加一個判斷是否有數(shù)據(jù)發(fā)送。
1.我們沒有學(xué)習(xí)并發(fā)編程,所以我們的代碼用循環(huán)來實現(xiàn)即你的服務(wù)端接受完一個客戶端的數(shù)據(jù)以后,你可以繼續(xù)去接收另一個客戶端的數(shù)據(jù)
2.除此之外我們還加上了一行代碼用于判斷你的端口是否被占用這樣就可以減少出錯
3.我在加上一個客戶端之后我們會出現(xiàn)另外一個問題就是我們到底需不需要另一個客戶端傳輸?shù)臄?shù)據(jù)或者說我們的多個客戶端到底有沒有都發(fā)送數(shù)據(jù),所以我們這里需要一個try和except先去判斷一下
--------------------------------服務(wù)端----------------------- import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #判斷接口是否被占用 phone.bind(("172.20.10.4",3234)) phone.listen(5) print("starting") while True: #沒有學(xué)習(xí)并發(fā)編程 沒辦法執(zhí)行代碼后返回到這繼續(xù)執(zhí)行,所以用循環(huán)解決 conn,client_add = phone.accept() print(client_add) while True: try: data=conn.recv(1024) if not data:break print("客戶端數(shù)據(jù)",data) conn.send(data.upper()) except ConnectionResetError : break conn.close() phone.close()
-----------------客戶端1----------------- import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(("172.20.10.4",3234)) while True: msg = input(">>>:").strip() if not msg: continue #若輸入空則繼續(xù)循環(huán) phone.send(msg.encode("utf-8")) # print("if send none") data=phone.recv(1024) print(data) # print(data.decode("utf-8")) phone.close()
-----------------------------客戶端2--------------------- import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.connect(("172.20.10.4",3234)) while True: msg = input(">>>:").strip() if not msg: continue #若輸入空則繼續(xù)循環(huán) phone.send(msg.encode("utf-8")) # print("if send none") data=phone.recv(1024) print(data) # print(data.decode("utf-8")) phone.close()
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Python使用random.shuffle()打亂列表順序的方法
今天小編就為大家分享一篇Python使用random.shuffle()打亂列表順序的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-11-11python使用tensorflow深度學(xué)習(xí)識別驗證碼
這篇文章主要介紹了python使用tensorflow深度學(xué)習(xí)識別驗證碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04python+excel接口自動化獲取token并作為請求參數(shù)進行傳參操作
這篇文章主要介紹了python+excel接口自動化獲取token并作為請求參數(shù)進行傳參操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11

python 如何把classification_report輸出到csv文件