Python中的網(wǎng)絡(luò)通信

概述

? ? ? ? 在我們平時(shí)生活工作中,常常會(huì)接觸到網(wǎng)絡(luò)通信的內(nèi)容寻行,不管你是普通的用戶点晴,還是通信行業(yè)內(nèi)的開發(fā)人員感凤,都無法避免與網(wǎng)絡(luò)通信打交道。我在初步學(xué)習(xí)python的過程中粒督,對(duì)python的網(wǎng)絡(luò)通信問題做了總結(jié)陪竿,所以寫下這篇文章作為記錄,也希望能給其他初學(xué)者一些引導(dǎo)和啟發(fā)屠橄。這篇文章的主要內(nèi)容如下:

????1. 在深入講解之前族跛,我們先介紹一些背景信息;

????2. 介紹套接字的概念锐墙;

????3. 展示如何用Python來實(shí)現(xiàn)簡單的網(wǎng)絡(luò)應(yīng)用程序礁哄。

客戶端/服務(wù)器架構(gòu)(C/S架構(gòu))

????????什么是客戶端/服務(wù)器架構(gòu)?總的來說溪北,某一個(gè)特定的對(duì)象桐绒,并沒有嚴(yán)格的客戶端或者服務(wù)器之分,區(qū)分的標(biāo)準(zhǔn)在于之拨,在實(shí)現(xiàn)網(wǎng)絡(luò)通信的過程中茉继,該對(duì)象的行為模式?jīng)Q定了它是客戶端還是服務(wù)端。

服務(wù)器:為一個(gè)或者多個(gè)客戶端(用戶)提供所需“服務(wù)"的一系列硬件或者軟件蚀乔。工作流程可以簡單概括為:等待請(qǐng)求烁竭、響應(yīng)并提供服務(wù)、等待下一個(gè)請(qǐng)求吉挣。

客戶端:因特定請(qǐng)求而聯(lián)系服務(wù)器派撕,接收服務(wù)并處理相關(guān)事務(wù)的一方婉弹。客戶端可以持續(xù)向服務(wù)器發(fā)送請(qǐng)求腥刹,也可以在結(jié)束事務(wù)請(qǐng)求后不再發(fā)出請(qǐng)求马胧。


因特網(wǎng)上典型的C/S架構(gòu)

通信端點(diǎn)與套接字(socket)

????????在服務(wù)器相應(yīng)客戶端的請(qǐng)求之前,雙方需要進(jìn)行一系列的準(zhǔn)備工作衔峰。首先需要?jiǎng)?chuàng)建一個(gè)通信端點(diǎn)佩脊,服務(wù)器通過該通信端點(diǎn)監(jiān)聽客戶端的請(qǐng)求(當(dāng)然,實(shí)際的網(wǎng)絡(luò)通信中垫卤,處理不同類型的消息會(huì)使用不同類型的通信端點(diǎn)威彰,從而進(jìn)行區(qū)分)。

????????在網(wǎng)絡(luò)通信中穴肘,我們常用的一種通信端點(diǎn)為套接字(socket)歇盼,在通信開始之前,網(wǎng)絡(luò)應(yīng)用程序都需要?jiǎng)?chuàng)建套接字评抚。

套接字的分類

? ? 1. 基于文件的套接字

????????UNIX 套接字是我們所講的套接字的第一個(gè)家族豹缀,并且擁有一個(gè)“家族名字”:AF_UNIX(又名 AF_LOCAL,在 POSIX1.g 標(biāo)準(zhǔn)中指定),它代表地址家族(address family):UNIX慨代。

????????包括 Python 在內(nèi)的大多數(shù)受歡迎的平臺(tái)都使用術(shù)語地址家族及其縮寫 AF邢笙;其他比較舊的系統(tǒng)可能會(huì)將地址家族表示成域(domain)或協(xié)議家族(protocol family),并使用其縮寫 PF 而非 AF侍匙。類似地,AF_LOCAL(在 2000~2001 年標(biāo)準(zhǔn)化)將代替 AF_UNIX氮惯。然而,考慮到后向兼容性,很多系統(tǒng)都同時(shí)使用二者想暗,只是對(duì)同一個(gè)常數(shù)使用不同的別名妇汗。Python 本身仍然在使用 AF_UNIX。

? ? 2. 面向網(wǎng)絡(luò)的套接字

????????它也有自己的家族名字 AF_INET说莫,或者地址家族:因特網(wǎng)杨箭。另一個(gè)地址家族 AF_INET6 用于第 6 版因特網(wǎng)協(xié)議(IPv6)尋址。(還有其他的地址家族储狭,這些要么是專業(yè)的互婿、過時(shí)的、很少使用的,要么是仍未實(shí)現(xiàn)的晶密。)在所有的地址家族之中,目前 AF_INET 是使用得最廣泛的。

????????總的來說,Python 只支持 AF_UNIX模她、AF_NETLINK稻艰、AF_TIPC 和 AF_INET 家族。下面的內(nèi)容中,我們將使用 AF_INET侈净。

套接字地址:主機(jī)-端口對(duì)

? ? ? ? 正如我們?cè)诂F(xiàn)實(shí)生活中打電話一樣尊勿,套接字的通信需要一些記號(hào)用作識(shí)別功能僧凤。我們打電話的時(shí)候,可以通過區(qū)號(hào)和電話號(hào)碼的組合找到要呼叫的用戶元扔;在socket通信中躯保,我們通過主機(jī)-端口對(duì)找到通信的對(duì)象。

? ? ? ? 我們都知道澎语,通過url或者ip地址途事,我們可以在互聯(lián)網(wǎng)中找到特定的主機(jī)。在每一臺(tái)主機(jī)中擅羞,不同的端口號(hào)會(huì)用作不同的通信用途尸变。只要確定的主機(jī)和端口號(hào),就可以在網(wǎng)絡(luò)中唯一確定一個(gè)”通信端點(diǎn)“减俏,也就是找到了所要進(jìn)行通信的套接字的地址了召烂。

? ? ? ? 需要說明的是,有效的端口號(hào)范圍是0~65535(小于1024的端口號(hào)預(yù)留給了系統(tǒng))娃承。一般來說奏夫,其余的端口號(hào)我們都可以根據(jù)實(shí)際的需要進(jìn)行使用。

面向連接的套接字與無連接的套接字

? ? 1. 面向連接的套接字(TCP)

? ? ? ? 也稱為虛擬電路流套接字历筝。主要提供序列化的酗昼、可靠的、不重復(fù)的數(shù)據(jù)漫谷,它可以將消息拆分成多個(gè)片段仔雷,確保每一條片段都順利到達(dá)目的地,然后按照順序組合在一起舔示,最后將完整的消息傳遞給正在等待的應(yīng)用程序碟婆。

? ? ? ? 實(shí)現(xiàn)的主要協(xié)議是傳輸控制協(xié)議(TCP)。創(chuàng)建TCP套接字時(shí)惕稻,必須使用SOCK_STREAM作為套接字類型竖共。

? ? 2. 無連接的套接字(UDP)

????????又稱為數(shù)據(jù)報(bào)類型的套接字。在傳輸過程中無法保證其順序性俺祠、可靠性公给、重復(fù)性,事實(shí)上所發(fā)送的報(bào)文有可能最后并沒有到達(dá)蜘渣,也有可能存在重復(fù)的消息淌铐。

? ? ? ? 我們之所以還繼續(xù)使用數(shù)據(jù)報(bào),這是相對(duì)于面向連接的套接字來看的蔫缸。由于維護(hù)TCP連接需要大量的開銷腿准,發(fā)送數(shù)據(jù)報(bào)能夠保證成本更加”低廉“,所以通常能提供更好的性能拾碌,并且可能更適合某一些類型的應(yīng)用程序吐葱。

? ? ? ? 實(shí)現(xiàn)的主要協(xié)議是用戶數(shù)據(jù)報(bào)協(xié)議(UDP)街望。創(chuàng)建UDP套接字,必須使用SOCK_DGRAM作為套接字類型弟跑。

Python中的網(wǎng)絡(luò)編程

socket()模塊函數(shù)

????????要?jiǎng)?chuàng)建套接字灾前,必須使用socket.socket()函數(shù),它的一般語法如下:

socket(socket_family, socket_type, protocol=0)

????????其中孟辑,socket_family是AF_UNIX或者AF_INET哎甲,socket_type是SOCK_STREAM或者SOCK_DGRAM,protocol通常省略扑浸,默認(rèn)為0 烧给。

????????在python編程中,我們首先在文件最開始的地方引用需要用到的模塊喝噪,在這里础嫡,我們使用“from socket import *",通過這樣的引用酝惧,就可以向下面這樣直接創(chuàng)建套接字:

tcpSock = socket(AF_INET, SOCK_STREAM)

udpSock = socket(AF_INET, SOCK_DGRAM)

????????成功創(chuàng)建套接字后榴鼎,我們就可以調(diào)用套接字對(duì)象的內(nèi)置方法進(jìn)行其他的操作了。具體的內(nèi)容可以查看python的文檔晚唇。

TCP通信

1. 創(chuàng)建TCP服務(wù)器

? ? ? ? 以下是一個(gè)TCP服務(wù)器程序巫财,它接受客戶端發(fā)送的字符串,將其打上時(shí)間戳之后哩陕,再返回給客戶端平项。二話不說,先貼代碼:

TCP時(shí)間戳服務(wù)器

第1~4行:

????????聲明運(yùn)行環(huán)境悍及,導(dǎo)入socket模塊和time.ctime()闽瓢。

第6~10行:

? ? ? ? 指定主機(jī)地址、工作端口號(hào)心赶、接收緩存的長度扣讼。HOST和PORT共同組成ADDR,體現(xiàn)的就是上面我們所說的”主機(jī)-端口對(duì)“缨叫。服務(wù)器端的HOST為空椭符,表示它可以使用任意可用的地址。

第12~14行:

? ? ? ? 創(chuàng)建套接字 耻姥,把套接字綁定到服務(wù)器地址销钝,開啟TCP監(jiān)聽。

第16~32行:

? ? ? ? 進(jìn)入服務(wù)器的無限循環(huán)琐簇,不斷等待接收客戶端的連接蒸健。在第18行,我們通過accept()獲取到客戶端的tcpCliSock和addr,于是后續(xù)可以通過這個(gè)tcpCliSock專門處理該客戶端的事務(wù)(從而與其他請(qǐng)求的客戶端區(qū)分開來)纵装。在第22行,使用recv()接收消息据某,如果消息為空橡娄,則跳出循環(huán),關(guān)閉當(dāng)前客戶端的連接癣籽,然后繼續(xù)等待連接挽唉;如果不為空,則把消息解析出來筷狼,添加時(shí)間戳瓶籽,經(jīng)過重新編碼成ASCII字節(jié)后,通過send()發(fā)送回去給客戶端埂材。在這個(gè)程序里塑顺,第32行不會(huì)執(zhí)行,只是用于提醒編寫程序的人俏险,在使用這一套程序時(shí)严拒,必須要考慮到合理科學(xué)的退出方式,正確地調(diào)用close()方法竖独。

? ? ? ? 這里需要強(qiáng)調(diào)的是裤唠,由于python的編碼問題,所以我們的消息在主機(jī)端時(shí)要進(jìn)行解碼后才能正確顯示(如decode())莹痢,進(jìn)行編碼后才能發(fā)送到網(wǎng)絡(luò)端去(如encode()种蘸,bytes())。不管是在服務(wù)器還是客戶端竞膳,我們都需要考慮到這個(gè)情況航瞭。

2. 創(chuàng)建TCP客戶端

? ? ? ? 創(chuàng)建客戶端比服務(wù)器要簡單很多《ゲ拢客戶端與服務(wù)器建立連接沧奴,發(fā)送字符串給服務(wù)器,從服務(wù)器接收添加了時(shí)間戳的消息并打印长窄。發(fā)送空字符串即可關(guān)閉套接字滔吠,退出這次連接。代碼實(shí)例如下:

TCP時(shí)間戳客戶端

第1~3行:

????????聲明運(yùn)行環(huán)境挠日,導(dǎo)入socket模塊疮绷。

第5~9行:

????????指定主機(jī)地址、工作端口號(hào)嚣潜、接收緩存的長度冬骚。HOST和PORT共同組成ADDR,體現(xiàn)的就是上面我們所說的”主機(jī)-端口對(duì)“。這里的HOST為服務(wù)器端所在主機(jī)的地址只冻,由于我是在本地進(jìn)行通信測試的庇麦,所以地址設(shè)置為127.0.0.1(localhost)。在實(shí)際網(wǎng)絡(luò)通信的時(shí)候喜德,根據(jù)具體的情況進(jìn)行相應(yīng)的修改山橄。客戶端填寫的PORT必須與服務(wù)器填寫的PORT對(duì)應(yīng)才能正常通信舍悯。

第11~12行:

????????創(chuàng)建套接字 航棱,主動(dòng)調(diào)用并通過connect()連接到服務(wù)器。

第14~25行:

? ? ? ? 進(jìn)行無限循環(huán):客戶端填寫要發(fā)送的消息萌衬,發(fā)送后等待接收服務(wù)器的回復(fù)饮醇,接收到結(jié)果后將結(jié)果打印。當(dāng)客戶端輸入的內(nèi)容為空秕豫,或者服務(wù)器斷開連接朴艰、客戶端接收失敗時(shí),即退出循環(huán)混移,調(diào)用close()函數(shù)呵晚,關(guān)閉客戶端的套接字。

? ? ? ? 同樣的沫屡,發(fā)送消息前饵隙,我們需要對(duì)數(shù)據(jù)進(jìn)行編碼,接收的結(jié)果沮脖,也需要進(jìn)行解碼后才能正常顯示出來金矛。如果我們想要將代碼改成相應(yīng)的ipv6的形式,我們只需要把HOST改成“::1”勺届,sock_family改成AF_INET6即可驶俊。

UDP通信

1. 創(chuàng)建UDP服務(wù)器

? ? ? ? UDP服務(wù)器實(shí)現(xiàn)的功能與TCP基本一致,主要的區(qū)別在于UDP服務(wù)器不是面向連接的免姿,所以只需要等待客戶端的請(qǐng)求饼酿,回復(fù)消息即可,不需要將成功連接的客戶端“轉(zhuǎn)換”到一個(gè)獨(dú)立的套接字的操作胚膊。示例代碼如下:

UDP時(shí)間戳服務(wù)器

第1~4行:

????????聲明運(yùn)行環(huán)境故俐,導(dǎo)入socket模塊和time.ctime()

第6~10行:

? ? ? ? 與TCP相同紊婉,指定主機(jī)地址药版、工作端口號(hào)、接收緩存的長度喻犁。HOST和PORT共同組成ADDR槽片,體現(xiàn)的就是上面我們所說的”主機(jī)-端口對(duì)“何缓。服務(wù)器端的HOST為127.0.0.1,表示它使用本地主機(jī)地址还栓。

第12~13行:

????????創(chuàng)建套接字 碌廓,把套接字綁定到服務(wù)器地址,綁定后直接等待接收剩盒,不需要監(jiān)聽氓皱。

第15~24行:

????????進(jìn)入服務(wù)器的無限循環(huán),不斷等待接收客戶端的連接勃刨。在第17行,使用recvfrom()接收消息股淡,同時(shí)獲取通信客戶端的地址對(duì)信息身隐。緊接著把消息解析出來,添加時(shí)間戳唯灵,經(jīng)過重新編碼成ASCII字節(jié)后贾铝,通過sendto()發(fā)送回去給客戶端,此時(shí)由于服務(wù)器沒有與客戶端維護(hù)連接埠帕,所以要指定發(fā)送的地址對(duì)信息垢揩。同樣的,在這個(gè)程序里敛瓷,第24行不會(huì)執(zhí)行叁巨,只是用于提醒編寫程序的人,在使用這一套程序時(shí)呐籽,必須要考慮到合理科學(xué)的退出方式锋勺,正確地調(diào)用close()方法。

2. 創(chuàng)建UDP客戶端

? ? ? ? 原理非常簡單狡蝶,上面都有提及到庶橱,就不作詳細(xì)說明了。直接貼代碼:

UDP時(shí)間戳客戶端

關(guān)于服務(wù)器退出的問題

? ? ? ? 最后再提以下服務(wù)器退出的問題贪惹。在開發(fā)中苏章,一種相對(duì)比較友好的退出方式是:將服務(wù)器的while部分放在一個(gè)try-excepttry子句中,并監(jiān)控EOFError和KeyboardInterrupt異常奏瞬,這樣就可以在except或者finally子句中關(guān)閉服務(wù)器的套接字枫绅。



參考內(nèi)容:

《Python核心編程(第三版)》[美] Wesley Chun 著,孫波翔硼端、李斌撑瞧、李晗 譯。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末显蝌,一起剝皮案震驚了整個(gè)濱河市预伺,隨后出現(xiàn)的幾起案子订咸,更是在濱河造成了極大的恐慌,老刑警劉巖酬诀,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件脏嚷,死亡現(xiàn)場離奇詭異,居然都是意外死亡瞒御,警方通過查閱死者的電腦和手機(jī)父叙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肴裙,“玉大人趾唱,你說我怎么就攤上這事◎吲常” “怎么了甜癞?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長宛乃。 經(jīng)常有香客問我悠咱,道長,這世上最難降的妖魔是什么征炼? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任析既,我火速辦了婚禮,結(jié)果婚禮上谆奥,老公的妹妹穿的比我還像新娘眼坏。我一直安慰自己,他們只是感情好酸些,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布空骚。 她就那樣靜靜地躺著,像睡著了一般擂仍。 火紅的嫁衣襯著肌膚如雪囤屹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天逢渔,我揣著相機(jī)與錄音肋坚,去河邊找鬼。 笑死肃廓,一個(gè)胖子當(dāng)著我的面吹牛智厌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播盲赊,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼铣鹏,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了哀蘑?” 一聲冷哼從身側(cè)響起诚卸,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤葵第,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后合溺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體卒密,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年棠赛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了哮奇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡睛约,死狀恐怖鼎俘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情辩涝,我是刑警寧澤贸伐,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站膀值,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏误辑。R本人自食惡果不足惜沧踏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望巾钉。 院中可真熱鬧翘狱,春花似錦、人聲如沸砰苍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赚导。三九已至茬缩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吼旧,已是汗流浹背凰锡。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留圈暗,地道東北人掂为。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像员串,于是被迫代替她去往敵國和親勇哗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 最近在學(xué)習(xí)Python看了一篇文章寫得不錯(cuò)寸齐,是在腳本之家里的欲诺,原文如下抄谐,很有幫助: 一、網(wǎng)絡(luò)知識(shí)的一些介紹 soc...
    qtruip閱讀 2,688評(píng)論 0 6
  • 一瞧栗、網(wǎng)絡(luò)各個(gè)協(xié)議:TCP/IP斯稳、SOCKET、HTTP等 網(wǎng)絡(luò)七層由下往上分別為物理層迹恐、數(shù)據(jù)鏈路層挣惰、網(wǎng)絡(luò)層、傳輸層...
    杯水救車薪閱讀 2,258評(píng)論 0 17
  • 參考:http://www.2cto.com/net/201611/569006.html TCP HTTP UD...
    F麥子閱讀 2,940評(píng)論 0 14
  • Socket基礎(chǔ)概念 網(wǎng)絡(luò)中進(jìn)程之間如何通信竖幔? 網(wǎng)絡(luò)中進(jìn)程之間如何通信?首要解決的問題是如何唯一標(biāo)識(shí)一個(gè)進(jìn)程是偷,否則...
    DiamondsAndRust閱讀 4,739評(píng)論 2 54
  • 1:機(jī)票 2:簽證(最好是在國內(nèi)辦好了去拳氢,推薦康輝旅行社代辦送簽,8個(gè)工作日寄回) 3:酒店(根據(jù)自己要求定蛋铆,不一...
    王小煩不慌閱讀 150評(píng)論 0 0