肝!Python 网络编程
什么是網絡?
網絡就是一種輔助雙方或者多方能夠連接在一起,然后可以進行數據傳遞的工具。
就是為了聯通多方然后進行通信用的,即把數據從一方傳遞給另外一方,為了讓在不同的電腦上運行的軟件,之間能夠互相傳遞數據,就需要借助網絡的功能。
網絡通信IP地址:用來在網絡中標記一臺電腦,比如 192.168.1.1 ,在本地局域網上是唯一的。
不同電腦上的進程之間如何通信?
首要解決的問題是如何唯一標識一個進程,否則通信無從談起!
在1臺電腦上可以通過進程號 PID 來唯一標識一個進程,但是在網絡中這是行不通的。
其實 TCP/IP 協議族已經幫我們解決了這個問題,網絡層的 ip地址 可以唯一標識網絡中的主機
而傳輸層的 協議+端口 可以唯一標識主機中的應用進程(進程)。
這樣利用 ip地址,協議,端口 就可以標識網絡的進程了,網絡中的進程通信就可以利用這個標志與其它進程進行交互。
什么是Socket?
Socket(簡稱 套接字) 是進程間通信的一種方式,它與其他進程間通信的一個主要不同是:
它能實現不同主機間的進程間通信,我們網絡上各種各樣的服務大多都是基于 Socket 來完成通信的
例如我們每天瀏覽 網頁、QQ 聊天、收發 email 等等。
socket()函數
了解了網絡,那在Python中我們是如何進行網絡編程呢?其實很簡單,在Python 中,我們用 socket 模塊中socket() 函數 來創建套接字,語法格式如下:
import?socket socket.socket(family,?type,?proto)參數:
family: 套接字家族可以是 AF_UNIX (同一臺機器進程間通信) 或者 AF_INET (Internet 進程間通信)
type: 套接字類型可以根據是面向連接的還是非連接分為SOCK_STREAM (流式套接字,主要用于 TCP 協議) 或SOCK_DGRAM (數據報套接字,主要用于 UDP 協議)
protocol: 一般不填默認為 0
創建 ?Socket(套接字)
套接字使用流程 與 文件的使用流程很類似
創建套接字
使用套接字收/發數據
關閉套接字
TCP Socket(TCP 套接字)
import?scoket#?創建TCP套接字 s?=?socket.socket(socket.AF_INET,?socket.SOCK_STREAM)#?套接字功能的使用 #?此處省略...s.close()UDP Socket(UDP套接字)
import?scoket#?創建UDP套接字 s?=?socket.socket(socket.AF_INET,?socket.SOCK_DGRAM)#?套接字功能的使用 #?此處省略...s.close()Socket套接字對象方法
| 服務器端套接字 | |
| socket.bind() | 綁定地址(host,port)到套接字, 在 AF_INET下,以元組(host,port)的形式表示地址。 |
| socket.listen() | 開始TCP監聽。backlog指定在拒絕連接之前,操作系統可以掛起的最大連接數量。該值至少為1,大部分應用程序設為5就可以了。 |
| socket.accept() | 被動接受TCP客戶端連接,(阻塞式)等待連接的到來 |
| 客戶端套接字 | |
| socket.connect() | 主動初始化TCP服務器連接。一般address的格式為元組(hostname, port),如果連接出錯,返回socket.error錯誤。 |
| socket.connect_ex() | connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常 |
| 公共用途的套接字函數 | |
| socket.recv() | 接收TCP數據,數據以字符串形式返回,bufsize指定要接收的最大數據量。flag提供有關消息的其他信息,通常可以忽略。 |
| socket.send() | 發送TCP數據,將string中的數據發送到連接的套接字。返回值是要發送的字節數量,該數量可能小于string的字節大小。 |
| socket.sendall() | 完整發送TCP數據,完整發送TCP數據。將string中的數據發送到連接的套接字,但在返回之前會嘗試發送所有數據。成功返回None,失敗則拋出異常。 |
| socket.recvfrom() | 接收UDP數據,與recv()類似,但返回值是(data,address)。其中data是包含接收數據的字符串,address是發送數據的套接字地址。 |
| socket.sendto() | 發送UDP數據,將數據發送到套接字,address是形式為(ipaddr,port)的元組,指定遠程地址。返回值是發送的字節數。 |
| socket.close() | 關閉套接字 |
| socket.getpeername() | 返回連接套接字的遠程地址。返回值通常是元組(ipaddr,port)。 |
| socket.getsockname() | 返回套接字自己的地址。通常是一個元組(ipaddr,port) |
| socket.setsockopt(level,optname,value) | 設置給定套接字選項的值。 |
| socket.getsockopt(level,optname[.buflen]) | 返回套接字選項的值。 |
| socket.settimeout(timeout) | 設置套接字操作的超時期,timeout是一個浮點數,單位是秒。值為None表示沒有超時期。一般,超時期應該在剛創建套接字時設置,因為它們可能用于連接的操作(如connect()) |
| socket.gettimeout() | 返回當前超時期的值,單位是秒,如果沒有設置超時期,則返回None。 |
| socket.fileno() | 返回套接字的文件描述符。 |
| socket.setblocking(flag) | 如果 flag 為 False,則將套接字設為非阻塞模式,否則將套接字設為阻塞模式(默認值)。非阻塞模式下,如果調用 recv() 沒有發現任何數據,或 send() 調用無法立即發送數據,那么將引起 socket.error 異常。 |
| socket.makefile() | 創建一個與該套接字相關連的文件 |
套接字對象方法,除了 makefile(),其他都與套接字專用的 Unix 系統調用相對應。
更多詳情可去 Python官方文檔 https://docs.python.org/zh-cn/3/library/socket.html?highlight=socket#socket-objects 查閱。
Socket 小案例
UDP聊天器
import?socketdef?send_msg(udp_socket):"""獲取鍵盤數據,并將其發送給對方"""#?1.?從鍵盤輸入數據msg?=?input("\n請輸入要發送的數據:")#?2.?輸入對方的ip地址dest_ip?=?input("\n請輸入對方的ip地址:")#?3.?輸入對方的portdest_port?=?int(input("\n請輸入對方的port:"))#?4.?發送數據udp_socket.sendto(msg.encode("utf-8"),?(dest_ip,?dest_port))def?recv_msg(udp_socket):"""接收數據并顯示"""#?1.?接收數據recv_msg?=?udp_socket.recvfrom(1024)#?2.?解碼recv_ip?=?recv_msg[1]recv_msg?=?recv_msg[0].decode("utf-8")#?3.?顯示接收到的數據print(">>>%s:%s"?%?(str(recv_ip),?recv_msg))def?main():#?1.?創建套接字udp_socket?=?socket.socket(socket.AF_INET,?socket.SOCK_DGRAM)#?2.?綁定本地信息udp_socket.bind(("localhost",?7890))while?True:#?3.?選擇功能print("="*30)print("1:發送消息")print("2:接收消息")print("="*30)op_num?=?input("請輸入要操作的功能序號:")#?4.?根據選擇調用相應的函數if?op_num?==?"1":send_msg(udp_socket)elif?op_num?==?"2":recv_msg(udp_socket)else:print("輸入有誤,請重新輸入...")if?__name__?==?"__main__":main()運行結果如下:
============================== 1:發送消息 2:接收消息 ============================== 請輸入要操作的功能序號:1請輸入要發送的數據:123請輸入對方的ip地址:10.73.30.48請輸入對方的port:7890 ============================== 1:發送消息 2:接收消息 ============================== 請輸入要操作的功能序號:2 >>>('10.73.30.48',?7890):123 ============================== 1:發送消息 2:接收消息 ==============================文件下載器
服務端 代碼如下:
import?sys from?socket?import?*def?get_file_content(file_name):"""獲取文件的內容"""try:with?open(file_name,?"rb")?as?f:content?=?f.read()return?contentexcept:print("沒有下載的文件:%s"?%?file_name)def?main():if?len(sys.argv)?!=?2:print("請按照如下方式運行:python3 xxx.py 7890")returnelse:#?運行方式為python3?xxx.py?7890port?=?int(sys.argv[1])#?創建sockettcp_server_socket?=?socket(AF_INET,?SOCK_STREAM)#?綁定本地信息?''空制字符串代表lockhost本地主機address?=?('',?port)tcp_server_socket.bind(address)#?將主動套接字變為被動套接字tcp_server_socket.listen(128)while?True:#?等待客戶端的鏈接,即為這個客戶端發送文件client_socket,?clientAddr?=?tcp_server_socket.accept()#?接收對方發送過來的數據recv_data?=?client_socket.recv(1024)??#?接收1024個字節file_name?=?recv_data.decode("utf-8")print("對方請求下載的文件名為:%s"?%?file_name)file_content?=?get_file_content(file_name)#?發送文件的數據給客戶端#?因為獲取打開文件時是以rb方式打開,所以file_content中的數據已經是二進制的格式,#?因此不需要encode編碼if?file_content:client_socket.send(file_content)#?關閉這個套接字client_socket.close()#?關閉監聽套接字tcp_server_socket.close()if?__name__?==?"__main__":main()客戶端 代碼如下:
from?socket?import?*def?main():#?創建sockettcp_client_socket?=?socket(AF_INET,?SOCK_STREAM)#?目的信息server_ip?=?input("請輸入服務器ip:")server_port?=?int(input("請輸入服務器port:"))#?鏈接服務器tcp_client_socket.connect((server_ip,?server_port))#?輸入需要下載的文件名file_name?=?input("請輸入要下載的文件名:")#?發送文件下載請求tcp_client_socket.send(file_name.encode("utf-8"))#?接收對方發送過來的數據,最大接收1024個字節(1K)recv_data?=?tcp_client_socket.recv(1024)#?print('接收到的數據為:',?recv_data.decode('utf-8'))#?如果接收到數據再創建文件,否則不創建if?recv_data:with?open("[接收]"+file_name,?"wb")?as?f:f.write(recv_data)#?關閉套接字tcp_client_socket.close()if?__name__?==?"__main__":main()python 文件下載器服務端.py 7890 開啟服務端
python 文件下載器客戶端.py 開啟客戶端
運行圖如下:
文件下載器Python Internet 模塊
以下列出了 Python 網絡編程的一些協議的重要模塊:
| HTTP | 網頁訪問 | 80 | httplib, urllib, xmlrpclib |
| NNTP | 閱讀和張貼新聞文章,俗稱為"帖子" | 119 | nntplib |
| FTP | 文件傳輸 | 20 | ftplib, urllib |
| SMTP | 發送郵件 | 25 | smtplib |
| POP3 | 接收郵件 | 110 | poplib |
| IMAP4 | 獲取郵件 | 143 | imaplib |
| Telnet | 命令行 | 23 | telnetlib |
| Gopher | 信息查找 | 70 | gopherlib, urllib |
總結
以上是生活随笔為你收集整理的肝!Python 网络编程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 老师吴恩达,身家又增20亿!
- 下一篇: 一个神级般的 Python 调试神器