13 - Python網絡編程入門

網絡編程入門

計算機網絡基礎

計算機網絡是獨立自主的計算機互聯而成的系統的總稱,組建計算機網絡最主要的目的是實現多臺計算機之間的通信和資源共享。今天計算機網絡中的設備和計算機網絡的用戶已經多得不可計數,而計算機網絡也可以稱得上是一個“復雜巨系統”,對于這樣的系統,我們不可能用一兩篇文章把它講清楚,有興趣的讀者可以自行閱讀Andrew S.Tanenbaum老師的經典之作《計算機網絡》或Kurose和Ross老師合著的《計算機網絡:自頂向下方法》來了解計算機網絡的相關知識。

計算機網絡發展史
  1. 1960s - 美國國防部ARPANET項目問世,奠定了分組交換網絡的基礎。

    在這里插入圖片描述

  2. 1980s - 國際標準化組織(ISO)發布OSI/RM,奠定了網絡技術標準化的基礎。

    在這里插入圖片描述

  3. 1990s - 英國人蒂姆·伯納斯-李發明了圖形化的瀏覽器,瀏覽器的簡單易用性使得計算機網絡迅速被普及。

    在沒有瀏覽器的年代,上網是這樣的。

    在這里插入圖片描述

    有了瀏覽器以后,上網是這樣的。

    在這里插入圖片描述

TCP/IP模型

實現網絡通信的基礎是網絡通信協議,這些協議通常是由互聯網工程任務組 (IETF)制定的。所謂“協議”就是通信計算機雙方必須共同遵從的一組約定,例如怎樣建立連接、怎樣互相識別等,網絡協議的三要素是:語法、語義和時序。構成我們今天使用的Internet的基礎的是TCP/IP協議族,所謂協議族就是一系列的協議及其構成的通信模型,我們通常也把這套東西稱為TCP/IP模型。與國際標準化組織發布的OSI/RM這個七層模型不同,TCP/IP是一個四層模型,也就是說,該模型將我們使用的網絡從邏輯上分解為四個層次,自底向上依次是:網絡接口層、網絡層、傳輸層和應用層,如下圖所示。

在這里插入圖片描述

IP通常被翻譯為網際協議,它服務于網絡層,主要實現了尋址和路由的功能。接入網絡的每一臺主機都需要有自己的IP地址,IP地址就是主機在計算機網絡上的身份標識。當然由于IPv4地址的匱乏,我們平常在家里、辦公室以及其他可以接入網絡的公共區域上網時獲得的IP地址并不是全球唯一的IP地址,而是一個局域網(LAN)中的內部IP地址,通過網絡地址轉換(NAT)服務我們也可以實現對網絡的訪問。計算機網絡上有大量的被我們稱為“路由器”的網絡中繼設備,它們會存儲轉發我們發送到網絡上的數據分組,讓從源頭發出的數據最終能夠找到傳送到目的地通路,這項功能就是所謂的路由。

TCP全稱傳輸控制協議,它是基于IP提供的尋址和路由服務而建立起來的負責實現端到端可靠傳輸的協議,之所以將TCP稱為可靠的傳輸協議是因為TCP向調用者承諾了三件事情:

  1. 數據不傳丟不傳錯(利用握手、校驗和重傳機制可以實現)。
  2. 流量控制(通過滑動窗口匹配數據發送者和接收者之間的傳輸速度)。
  3. 擁塞控制(通過RTT時間以及對滑動窗口的控制緩解網絡擁堵)。
網絡應用模式
  1. C/S模式和B/S模式。這里的C指的是Client(客戶端),通常是一個需要安裝到某個宿主操作系統上的應用程序;而B指的是Browser(瀏覽器),它幾乎是所有圖形化操作系統都默認安裝了的一個應用軟件;通過C或B都可以實現對S(服務器)的訪問。關于二者的比較和討論在網絡上有一大堆的文章,在此我們就不再浪費筆墨了。
  2. 去中心化的網絡應用模式。不管是B/S還是C/S都需要服務器的存在,服務器就是整個應用模式的中心,而去中心化的網絡應用通常沒有固定的服務器或者固定的客戶端,所有應用的使用者既可以作為資源的提供者也可以作為資源的訪問者。

基于HTTP協議的網絡資源訪問

HTTP(超文本傳輸協議)

HTTP是超文本傳輸協議(Hyper-Text Transfer Proctol)的簡稱,維基百科上對HTTP的解釋是:超文本傳輸協議是一種用于分布式、協作式和超媒體信息系統的應用層協議,它是萬維網數據通信的基礎,設計HTTP最初的目的是為了提供一種發布和接收HTML頁面的方法,通過HTTP或者HTTPS(超文本傳輸安全協議)請求的資源由URI(統一資源標識符)來標識。關于HTTP的更多內容,我們推薦閱讀阮一峰老師的《HTTP 協議入門》,簡單的說,通過HTTP我們可以獲取網絡上的(基于字符的)資源,開發中經常會用到的網絡API(有的地方也稱之為網絡數據接口)就是基于HTTP來實現數據傳輸的。

JSON格式

JSONJavaScript Object Notation)是一種輕量級的數據交換語言,該語言以易于讓人閱讀的文字(純文本)為基礎,用來傳輸由屬性值或者序列性的值組成的數據對象。盡管JSON是最初只是Javascript中一種創建對象的字面量語法,但它在當下更是一種獨立于語言的數據格式,很多編程語言都支持JSON格式數據的生成和解析,Python內置的json模塊也提供了這方面的功能。由于JSON是純文本,它和XML一樣都適用于異構系統之間的數據交換,而相較于XML,JSON顯得更加的輕便和優雅。下面是表達同樣信息的XML和JSON,而JSON的優勢是相當直觀的。

XML的例子:

<?xml version="1.0" encoding="UTF-8"?>
<message><from>Alice</from><to>Bob</to><content>Will you marry me?</content>
</message>

JSON的例子:

{'from': 'Alice','to': 'Bob','content': 'Will you marry me?'
}
requests庫

requests是一個基于HTTP協議來使用網絡的第三庫,其官方網站有這樣的一句介紹它的話:“Requests是唯一的一個非轉基因的Python HTTP庫,人類可以安全享用。”簡單的說,使用requests庫可以非常方便的使用HTTP,避免安全缺陷、冗余代碼以及“重復發明輪子”(行業黑話,通常用在軟件工程領域表示重新創造一個已有的或是早已被優化過的基本方法)。前面的文章中我們已經使用過這個庫,下面我們還是通過requests來實現一個訪問網絡數據接口并從中獲取美女圖片下載鏈接然后下載美女圖片到本地的例子程序,程序中使用了天行數據提供的網絡API。

我們可以先通過pip安裝requests及其依賴庫。

pip install requests

如果使用PyCharm作為開發工具,可以直接在代碼中書寫import requests,然后通過代碼修復功能來自動下載安裝requests。

from time import time
from threading import Threadimport requests# 繼承Thread類創建自定義的線程類
class DownloadHanlder(Thread):def __init__(self, url):super().__init__()self.url = urldef run(self):filename = self.url[self.url.rfind('/') + 1:]resp = requests.get(self.url)with open('/Users/Hao/' + filename, 'wb') as f:f.write(resp.content)def main():# 通過requests模塊的get函數獲取網絡資源# 下面的代碼中使用了天行數據接口提供的網絡API# 要使用該數據接口需要在天行數據的網站上注冊# 然后用自己的Key替換掉下面代碼的中APIKey即可resp = requests.get('http://api.tianapi.com/meinv/?key=APIKey&num=10')# 將服務器返回的JSON格式的數據解析為字典data_model = resp.json()for mm_dict in data_model['newslist']:url = mm_dict['picUrl']# 通過多線程的方式實現圖片下載DownloadHanlder(url).start()if __name__ == '__main__':main()

基于傳輸層協議的套接字編程

套接字這個詞對很多不了解網絡編程的人來說顯得非常晦澀和陌生,其實說得通俗點,套接字就是一套用C語言寫成的應用程序開發庫,主要用于實現進程間通信和網絡編程,在網絡應用開發中被廣泛使用。在Python中也可以基于套接字來使用傳輸層提供的傳輸服務,并基于此開發自己的網絡應用。實際開發中使用的套接字可以分為三類:流套接字(TCP套接字)、數據報套接字和原始套接字。

TCP套接字

所謂TCP套接字就是使用TCP協議提供的傳輸服務來實現網絡通信的編程接口。在Python中可以通過創建socket對象并指定type屬性為SOCK_STREAM來使用TCP套接字。由于一臺主機可能擁有多個IP地址,而且很有可能會配置多個不同的服務,所以作為服務器端的程序,需要在創建套接字對象后將其綁定到指定的IP地址和端口上。這里的端口并不是物理設備而是對IP地址的擴展,用于區分不同的服務,例如我們通常將HTTP服務跟80端口綁定,而MySQL數據庫服務默認綁定在3306端口,這樣當服務器收到用戶請求時就可以根據端口號來確定到底用戶請求的是HTTP服務器還是數據庫服務器提供的服務。端口的取值范圍是0~65535,而1024以下的端口我們通常稱之為“著名端口”(留給像FTP、HTTP、SMTP等“著名服務”使用的端口,有的地方也稱之為“周知端口”),自定義的服務通常不使用這些端口,除非自定義的是HTTP或FTP這樣的著名服務。

下面的代碼實現了一個提供時間日期的服務器。

from socket import socket, SOCK_STREAM, AF_INET
from datetime import datetimedef main():# 1.創建套接字對象并指定使用哪種傳輸服務# family=AF_INET - IPv4地址# family=AF_INET6 - IPv6地址# type=SOCK_STREAM - TCP套接字# type=SOCK_DGRAM - UDP套接字# type=SOCK_RAW - 原始套接字server = socket(family=AF_INET, type=SOCK_STREAM)# 2.綁定IP地址和端口(端口用于區分不同的服務)# 同一時間在同一個端口上只能綁定一個服務否則報錯server.bind(('192.168.1.2', 6789))# 3.開啟監聽 - 監聽客戶端連接到服務器# 參數512可以理解為連接隊列的大小server.listen(512)print('服務器啟動開始監聽...')while True:# 4.通過循環接收客戶端的連接并作出相應的處理(提供服務)# accept方法是一個阻塞方法如果沒有客戶端連接到服務器代碼不會向下執行# accept方法返回一個元組其中的第一個元素是客戶端對象# 第二個元素是連接到服務器的客戶端的地址(由IP和端口兩部分構成)client, addr = server.accept()print(str(addr) + '連接到了服務器.')# 5.發送數據client.send(str(datetime.now()).encode('utf-8'))# 6.斷開連接client.close()if __name__ == '__main__':main()

運行服務器程序后我們可以通過Windows系統的telnet來訪問該服務器,結果如下圖所示。

telnet 192.168.1.2 6789

在這里插入圖片描述

當然我們也可以通過Python的程序來實現TCP客戶端的功能,相較于實現服務器程序,實現客戶端程序就簡單多了,代碼如下所示。

from socket import socketdef main():# 1.創建套接字對象默認使用IPv4和TCP協議client = socket()# 2.連接到服務器(需要指定IP地址和端口)client.connect(('192.168.1.2', 6789))# 3.從服務器接收數據print(client.recv(1024).decode('utf-8'))client.close()if __name__ == '__main__':main()

需要注意的是,上面的服務器并沒有使用多線程或者異步I/O的處理方式,這也就意味著當服務器與一個客戶端處于通信狀態時,其他的客戶端只能排隊等待。很顯然,這樣的服務器并不能滿足我們的需求,我們需要的服務器是能夠同時接納和處理多個用戶請求的。下面我們來設計一個使用多線程技術處理多個用戶請求的服務器,該服務器會向連接到服務器的客戶端發送一張圖片。

服務器端代碼:

from socket import socket, SOCK_STREAM, AF_INET
from base64 import b64encode
from json import dumps
from threading import Threaddef main():# 自定義線程類class FileTransferHandler(Thread):def __init__(self, cclient):super().__init__()self.cclient = cclientdef run(self):my_dict = {}my_dict['filename'] = 'guido.jpg'# JSON是純文本不能攜帶二進制數據# 所以圖片的二進制數據要處理成base64編碼my_dict['filedata'] = data# 通過dumps函數將字典處理成JSON字符串json_str = dumps(my_dict)# 發送JSON字符串self.cclient.send(json_str.encode('utf-8'))self.cclient.close()# 1.創建套接字對象并指定使用哪種傳輸服務server = socket()# 2.綁定IP地址和端口(區分不同的服務)server.bind(('192.168.1.2', 5566))# 3.開啟監聽 - 監聽客戶端連接到服務器server.listen(512)print('服務器啟動開始監聽...')with open('guido.jpg', 'rb') as f:# 將二進制數據處理成base64再解碼成字符串data = b64encode(f.read()).decode('utf-8')while True:client, addr = server.accept()# 啟動一個線程來處理客戶端的請求FileTransferHandler(client).start()if __name__ == '__main__':main()

客戶端代碼:

from socket import socket
from json import loads
from base64 import b64decodedef main():client = socket()client.connect(('192.168.1.2', 5566))# 定義一個保存二進制數據的對象in_data = bytes()# 由于不知道服務器發送的數據有多大每次接收1024字節data = client.recv(1024)while data:# 將收到的數據拼接起來in_data += datadata = client.recv(1024)# 將收到的二進制數據解碼成JSON字符串并轉換成字典# loads函數的作用就是將JSON字符串轉成字典對象my_dict = loads(in_data.decode('utf-8'))filename = my_dict['filename']filedata = my_dict['filedata'].encode('utf-8')with open('/Users/Hao/' + filename, 'wb') as f:# 將base64格式的數據解碼成二進制數據并寫入文件f.write(b64decode(filedata))print('圖片已保存.')if __name__ == '__main__':main()

在這個案例中,我們使用了JSON作為數據傳輸的格式(通過JSON格式對傳輸的數據進行了序列化和反序列化的操作),但是JSON并不能攜帶二進制數據,因此對圖片的二進制數據進行了Base64編碼的處理。Base64是一種用64個字符表示所有二進制數據的編碼方式,通過將二進制數據每6位一組的方式重新組織,剛好可以使用0~9的數字、大小寫字母以及“+”和“/”總共64個字符表示從000000111111的64種狀態。維基百科上有關于Base64編碼的詳細講解,不熟悉Base64的讀者可以自行閱讀。

說明:上面的代碼主要為了講解網絡編程的相關內容因此并沒有對異常狀況進行處理,請讀者自行添加異常處理代碼來增強程序的健壯性。

UDP套接字

傳輸層除了有可靠的傳輸協議TCP之外,還有一種非常輕便的傳輸協議叫做用戶數據報協議,簡稱UDP。TCP和UDP都是提供端到端傳輸服務的協議,二者的差別就如同打電話和發短信的區別,后者不對傳輸的可靠性和可達性做出任何承諾從而避免了TCP中握手和重傳的開銷,所以在強調性能和而不是數據完整性的場景中(例如傳輸網絡音視頻數據),UDP可能是更好的選擇。可能大家會注意到一個現象,就是在觀看網絡視頻時,有時會出現卡頓,有時會出現花屏,這無非就是部分數據傳丟或傳錯造成的。在Python中也可以使用UDP套接字來創建網絡應用,對此我們不進行贅述,有興趣的讀者可以自行研究。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/41653.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/41653.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/41653.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Springweb詳解

Springweb詳解 一.springweb介紹 1.1 SpringWEB 特點 ? SpringWEB 是 spring 家族原生產品&#xff0c;與 IOC 容器等基礎設施無縫對接. ? 基于原生的 Servlet&#xff0c;提供了一個前端控制器 DispatcherServlet &#xff0c;開發者 無須額外開發控制器對象. ? 可以自…

【SQL】聚簇索引與?聚簇索引的區別

聚簇索引&#xff08;Clustered Index&#xff09;和非聚簇索引&#xff08;Non-Clustered Index&#xff09;是數據庫索引的兩種主要類型&#xff0c;它們在數據存儲和訪問方式上有顯著區別。 聚簇索引 數據存儲順序&#xff1a;聚簇索引將數據行按照索引鍵的順序進行存儲。…

VSCode打開其它IDE項目注釋顯示亂碼的解決方法

問題描述&#xff1a;VSCode打開Visual Studio&#xff08;或其它IDE&#xff09;工程&#xff0c;注釋亂碼&#xff0c;如下圖所示&#xff1a; 解決方法&#xff1a;點擊VSCode右下角的UTF-8&#xff0c;根據提示點擊“通過編碼重新打開”&#xff0c;再選擇GB2312&#xff0…

R語言數據分析案例42-基于時間序列模型對股票預測分析和研究

一、研究背景和意義 隨著全球經濟的不斷發展和數字化轉型的加速推進&#xff0c;科技公司在全球市場中扮演著日益重要的角色。其中&#xff0c;中國的阿里巴巴集團作為全球最大的電子商務公司之一&#xff0c;其業務范圍覆蓋電子商務、云計算、金融科技等多個領域。由于其在中…

AI革命:RAG技術引領未來智能

AI革命:RAG技術引領未來智能 在人工智能的浪潮中,一種名為RAG(Retrieval-Augmented Generation)的技術正在悄然改變我們的世界。這種技術通過整合外部知識庫,極大地增強了大型語言模型(LLM)的性能,為智能助手、聊天機器人等應用帶來了革命性的提升。 1 突破性的RAG技…

【問題記錄】Jenkins Pipeline讀取變量的各種方法

方法一 輸出docker image鏡像標簽給IMAGE_TAG def IMAGE_TAG sh(script: docker images | grep ${SERVER_NAME} | grep $NAME_SPACE | awk {print $2}|grep ${BUILD_NUMBER}, returnStdout: true) 另外&#xff0c;如果想輸出docker image命令執行結果給IMAGE_TAG def IMAG…

【python】PyQt5可視化開發,如何設計鼠標顯示的形狀?

?? 歡迎大家來到景天科技苑?? &#x1f388;&#x1f388; 養成好習慣&#xff0c;先贊后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者簡介&#xff1a;景天科技苑 &#x1f3c6;《頭銜》&#xff1a;大廠架構師&#xff0c;華為云開發者社區專家博主&#xff0c;…

通信施工安全員B類測試題含答案

1.全國人民代表大會常務委員會關于修改<中華人民共和國安全生產法>的決定》由中華人民共和國第十二屆全國人民代表大會常務委員會第十次會議通過&#xff0c;自( )起施行。 A、2002年11月1日 B、2014年8月31日C、2014年12月1日(正確答案) D、2015年1月01日 2.生產經營單…

JMeter:循環控制器While Controller的用法小結

前言 在之前的博文“JMeter案例優化&#xff1a;測試執行結束后&#xff0c;實現tearDown的幾種方式”中&#xff0c;嘗試了JMeter的循環控制器While Controller&#xff0c;發現還有點小復雜&#xff0c;將學習過程記錄下來&#xff0c;免得遺忘。 注&#xff1a;我使用的是…

《C++20設計模式》外觀模式

文章目錄 一、前言二、實現1、UML類圖2、實現 一、前言 一句話總結外觀模式&#xff1a;簡化接口&#xff0c;或者簡化流程。&#x1f642; 相關代碼可以在這里&#xff0c;如有幫助給個star&#xff01;AidenYuanDev/design_patterns_in_modern_Cpp_20 二、實現 原來需要很…

動手學深度學習(Pytorch版)代碼實踐 -循環神經網絡-54~55循環神經網絡的從零開始實現和簡潔實現

54循環神經網絡的從零開始實現 import math import torch from torch import nn from torch.nn import functional as F from d2l import torch as d2l import matplotlib.pyplot as plt import liliPytorch as lp# 讀取H.G.Wells的時光機器數據集 batch_size, num_steps 32, …

多特征線性回歸

目錄 一、多特征符號意義說明&#xff1a;二、多特征模型表示&#xff1a;三、Numpy向量表示、內積計算&#xff1a;1.向量表示&#xff1a;2.內積計算&#xff1a; 四、多元線性回歸梯度下降算法&#xff1a; 一、多特征符號意義說明&#xff1a; x下標j&#xff1a;表示第j個…

怎么做外貿推廣:10個詳細教程和工具

1. 介紹 1.1 什么是外貿推廣 外貿推廣指的是將產品或服務推廣到國際市場的過程。它的主要目的是吸引海外客戶&#xff0c;增加銷售額&#xff0c;并擴大企業的全球影響力。外貿推廣不僅僅是銷售產品&#xff0c;它還包括品牌建設、市場研究和客戶關系管理。 谷歌外貿推廣案例…

機器學習---線性回歸

1、線性回歸 例如&#xff1a;對于一個房子的價格&#xff0c;其影響因素有很多&#xff0c;例如房子的面積、房子的臥室數量、房子的衛生間數量等等都會影響房子的價格。這些影響因子不妨用 x i x_{i} xi?表示&#xff0c;那么房價 y y y可以用如下公式表示&#xff1a; y …

吳恩達機器學習 第三課 week3 強化學習(月球著陸器自動著陸)

目錄 01 學習目標 02 概念 2.1 強化學習 2.2 深度Q學習&#xff08;Deep Q-Learning &#xff09; 03 問題描述 04 算法中的概念及原理 05 月球著陸器自動著陸的算法實現 06 拓展&#xff1a;基于pytorch實現月球著陸器著陸 07 總結 寫在最前&#xff1a;關于強化學習…

python conda查看源,修改源

查看源 conda config --show-sources 修改源 可以直接vim .condarc修改源&#xff0c;

Shell學習——Shell變量

文章目錄 Shell變量使用變量只讀變量刪除變量變量類型字符串變量&#xff1a; 在 Shell中&#xff0c;變量通常被視為字符串。整數變量&#xff1a; 在一些Shell中&#xff0c;你可以使用 declare 或 typeset 命令來聲明整數變量。數組變量&#xff1a; Shell 也支持數組&#…

平價貓糧新選擇!福派斯鮮肉貓糧,讓貓咪享受美味大餐!

福派斯鮮肉貓糧&#xff0c;作為一款備受鏟屎官們青睞的貓糧品牌&#xff0c;憑借其卓越的品質和高性價比&#xff0c;為眾多貓主帶來了健康與美味的雙重享受。接下來&#xff0c;我們將從多個維度對這款貓糧進行解析&#xff0c;讓各位鏟屎官更加全面地了解它的魅力所在。 1?…

【三】ubuntu24虛擬機集群配置免密登陸

文章目錄 環境背景1. 配置域名映射2. 配置免密登錄2.1 在每臺機器上生成SSH密鑰對&#xff1a;2.2 將公鑰分發到其他機器&#xff1a;2.2.1 報錯問題2.2.2 修復方法 3. 驗證免密登錄在 ubuntu1 上&#xff1a;在 ubuntu2 上&#xff1a;在 ubuntu3 上&#xff1a; 測試連接 環境…

三級_02_網絡系統結構與設計的基本原則

1.下列關于接入技術特征的描述中&#xff0c;錯誤的是()。 無線統一網絡中AC如果發現某個AP出現故障&#xff0c;將自動調高周圍AP的發射功率以覆蓋出現的空洞 ADSL技術具有非對稱帶寬特性 APON是一種無線接入技術 Cable Modem利用頻分復用的方法將信道分為上行信道和下行信…