Python入門系列(十)——網(wǎng)絡(luò)

目錄:
一魁淳、TCP編程
二盆驹、UDP編程

Python 提供了兩個級別訪問的網(wǎng)絡(luò)服務(wù):
低級別的網(wǎng)絡(luò)服務(wù)支持基本的 Socket琅催,它提供了標準的 BSD Sockets API居凶,可以訪問底層操作系統(tǒng)Socket接口的全部方法。
高級別的網(wǎng)絡(luò)服務(wù)模塊 SocketServer藤抡, 它提供了服務(wù)器中心類侠碧,可以簡化網(wǎng)絡(luò)服務(wù)器的開發(fā)。SocketServer其實是在Socket基礎(chǔ)上的一個多線程升級缠黍,作為入門教程弄兜,我們不做涉及。

我們在此將socket編程方式分為面向連接的方式(即TCP)和不面向連接的方式(即UDP)進行分別討論。

一替饿、TCP編程

TCP(Transmission Control Protocol 傳輸控制協(xié)議)是一種面向連接的语泽、可靠的、基于字節(jié)流的傳輸層通信協(xié)議,對應(yīng)到編程中视卢,它的特點就是需要先建立連接踱卵,再進行數(shù)據(jù)傳輸。
在此盜一張很棒的圖解方便大家理解:


盜圖

然后据过,臨時為了演示需要惋砂,將一個日歷查看功能布在了服務(wù)端,可通過接受客戶端提交的請求绳锅,返回對應(yīng)的請求內(nèi)容西饵。當然,你完全可以根據(jù)自己的需要布置更加有意義的小程序替換這里鳞芙,如:nmap等罗标。

需要注意的是,socket在python3中的數(shù)據(jù)傳輸均使用bytes的方式积蜻,所以我們需要及時的進行編碼解碼操作。

其中socket的基本語法為socket.socket([family[, type[, proto]]])

family: 套接字家族可以使AF_UNIX或者AF_INET
type: 套接字類型可以根據(jù)是面向連接的還是非連接分為SOCK_STREAM或SOCK_DGRAM
protocol: 一般不填默認為0
作為入門系列我們不在這些概念上拓展彻消,具體用法參見以下完整實例:
#TCP服務(wù)端
import socket
import calendar

s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ip_port=('127.0.0.1',11111)      #定義綁定ip和端口
s.bind(ip_port)                  #綁定監(jiān)聽
s.listen(5)                      #最大連接數(shù)
while True:
    print('正在等待客戶端連接……')
    conn,addr=s.accept()         #接收連接請求
    print("接入地址: %s" % str(addr))
    msg='連接成功!\n【歡迎來到史上最辣雞的日歷系統(tǒng)】\n輸入"exit"退出本系統(tǒng)'
    conn.send(msg.encode())      #發(fā)送應(yīng)答信息
    while True:                  #持續(xù)接收數(shù)據(jù)
        data=conn.recv(1024)
        if data==b'exit':        #收到exit斷開連接
            break
        try:
            conn.send(calendar.month(2019, int(str(data.decode()))).encode())
        except IndexError:       #異常處理機制竿拆,防止用戶亂輸造成服務(wù)端崩潰
            pass
            conn.send('請正確輸入月份:(1-12)'.encode())
    conn.close()                 #斷開連接

#輸出
正在等待客戶端連接……
接入地址: ('127.0.0.1', 16942)
正在等待客戶端連接……
#TCP客戶端
import socket

c=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ip_port=('127.0.0.1',11111)     #定義訪問ip和端口
c.connect(ip_port)              #連接服務(wù)器

while True:
    data = c.recv(1024)  # 接收返回信息
    print(data.decode())
    msg=input('請輸入想要查看的月份: 例如:1\n>>>>>')
    c.send(msg.encode())
    if msg=='exit':             #用戶輸入exit時退出
        break

c.close()                       #斷開連接

#輸出:
連接成功!
【歡迎來到史上最辣雞的日歷系統(tǒng)】
輸入"exit"退出本系統(tǒng)
請輸入想要查看的月份: 例如:1
>>>>>1
    January 2019
Mo Tu We Th Fr Sa Su
    1  2  3  4  5  6
 7  8  9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31

請輸入想要查看的月份: 例如:1
>>>>>2
   February 2019
Mo Tu We Th Fr Sa Su
             1  2  3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28

請輸入想要查看的月份: 例如:1
>>>>>1111
請正確輸入月份:(1-12)
請輸入想要查看的月份: 例如:1
>>>>>exit

Process finished with exit code 0

其中有一處類型轉(zhuǎn)換是使用的int(str()),即bytes類型解碼轉(zhuǎn)字符串再轉(zhuǎn)數(shù)字的形式,暫時沒有找到更有效且穩(wěn)定的替換方案宾尚,在線求助各位大佬~

關(guān)于常用套接字函數(shù)在上面的例子中已通過注釋的形式進行了說明丙笋,在此進行統(tǒng)一整理:

#服務(wù)器端套接字
s.bind()
綁定地址(host,port)到套接字, 在AF_INET下,以元組(host,port)的形式表示地址煌贴。
s.listen()
開始TCP監(jiān)聽御板。backlog指定在拒絕連接之前,操作系統(tǒng)可以掛起的最大連接數(shù)量牛郑。該值至少為1怠肋,大部分應(yīng)用程序設(shè)為5就可以了。
s.accept()
被動接受TCP客戶端連接,(阻塞式)等待連接的到來

#客戶端套接字
s.connect()
主動初始化TCP服務(wù)器連接淹朋,笙各。一般address的格式為元組(hostname,port),如果連接出錯础芍,返回socket.error錯誤杈抢。
s.connect_ex()
connect()函數(shù)的擴展版本,出錯時返回出錯碼,而不是拋出異常

#公共用途的套接字函數(shù)
s.recv()
接收TCP數(shù)據(jù),數(shù)據(jù)以字符串形式返回仑性,bufsize指定要接收的最大數(shù)據(jù)量惶楼。flag提供有關(guān)消息的其他信息,通常可以忽略歼捐。
s.send()
發(fā)送TCP數(shù)據(jù)何陆,將string中的數(shù)據(jù)發(fā)送到連接的套接字。返回值是要發(fā)送的字節(jié)數(shù)量窥岩,該數(shù)量可能小于string的字節(jié)大小甲献。
s.sendall()
完整發(fā)送TCP數(shù)據(jù),完整發(fā)送TCP數(shù)據(jù)颂翼。將string中的數(shù)據(jù)發(fā)送到連接的套接字晃洒,但在返回之前會嘗試發(fā)送所有數(shù)據(jù)。成功返回None朦乏,失敗則拋出異常球及。
s.recvfrom()
接收UDP數(shù)據(jù),與recv()類似呻疹,但返回值是(data,address)吃引。其中data是包含接收數(shù)據(jù)的字符串,address是發(fā)送數(shù)據(jù)的套接字地址刽锤。
s.sendto()
發(fā)送UDP數(shù)據(jù)镊尺,將數(shù)據(jù)發(fā)送到套接字,address是形式為(ipaddr并思,port)的元組庐氮,指定遠程地址。返回值是發(fā)送的字節(jié)數(shù)宋彼。
s.close()
關(guān)閉套接字
s.getpeername()
返回連接套接字的遠程地址弄砍。返回值通常是元組(ipaddr,port)。
s.getsockname()
返回套接字自己的地址输涕。通常是一個元組(ipaddr,port)
s.setsockopt(level,optname,value)
設(shè)置給定套接字選項的值音婶。
s.getsockopt(level,optname[.buflen])
返回套接字選項的值。
s.settimeout(timeout)
設(shè)置套接字操作的超時期莱坎,timeout是一個浮點數(shù)衣式,單位是秒。值為None表示沒有超時期檐什。一般瞳收,超時期應(yīng)該在剛創(chuàng)建套接字時設(shè)置,因為它們可能用于連接的操作(如connect())
s.gettimeout()
返回當前超時期的值厢汹,單位是秒螟深,如果沒有設(shè)置超時期,則返回None烫葬。
s.fileno()
返回套接字的文件描述符界弧。
s.setblocking(flag)
如果flag為0凡蜻,則將套接字設(shè)為非阻塞模式,否則將套接字設(shè)為阻塞模式(默認值)垢箕。非阻塞模式下划栓,如果調(diào)用recv()沒有發(fā)現(xiàn)任何數(shù)據(jù),或send()調(diào)用無法立即發(fā)送數(shù)據(jù)条获,那么將引起socket.error異常忠荞。
s.makefile()
創(chuàng)建一個與該套接字相關(guān)連的文件

二、UDP編程

UDP 是User Datagram Protocol的簡稱帅掘, 中文名是用戶數(shù)據(jù)報協(xié)議委煤,是OSI(Open System Interconnection,開放式系統(tǒng)互聯(lián)) 參考模型中一種無連接的傳輸層協(xié)議修档,提供面向事務(wù)的簡單不可靠信息傳送服務(wù)碧绞。對應(yīng)到編程中,就是不需要連接的建立吱窝,直接進行數(shù)據(jù)傳輸讥邻。
我們直接改寫上面的例子進行對比講解:

#服務(wù)端
import socket
import calendar

s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ip_port=('127.0.0.1',22222)      #定義綁定ip和端口
s.bind(ip_port)                  #綁定監(jiān)聽
while True:
    print('UDP服務(wù)端監(jiān)聽開啟……\n')
    data,addr = s.recvfrom(1024) #recvfrom()獲取數(shù)據(jù)和地址
    if data==b'exit':
        break
    print('Received from %s:%s.' % addr)
    try:                         #異常處理機制,防止用戶亂輸造成服務(wù)端崩潰
        s.sendto(calendar.month(2019, int(str(data.decode()))).encode(),addr)
    except:
        s.sendto('請正確輸入月份:(1-12)'.encode(),addr)
s.close()

#輸出:
UDP服務(wù)端監(jiān)聽開啟……

Received from 127.0.0.1:61716.
UDP服務(wù)端監(jiān)聽開啟……

Received from 127.0.0.1:61716.
UDP服務(wù)端監(jiān)聽開啟……

Received from 127.0.0.1:61716.
UDP服務(wù)端監(jiān)聽開啟……
#客戶端
import socket

c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ip_port = ('127.0.0.1', 22222)  #定義訪問ip和端口
print('【歡迎來到史上最辣雞的日歷系統(tǒng)】\n輸入"exit"退出本系統(tǒng)')
while True:
    msg=input('請輸入想要查看的月份: 例如:1\n>>>>>')
    if msg=='exit':
        break
    c.sendto(msg.encode(), ip_port)
    data=c.recv(1024)           #接收服務(wù)器返回數(shù)據(jù)
    print(data.decode())
c.close()                       #斷開連接

#輸出:
【歡迎來到史上最辣雞的日歷系統(tǒng)】
輸入"exit"退出本系統(tǒng)
請輸入想要查看的月份: 例如:1
>>>>>1
    January 2019
Mo Tu We Th Fr Sa Su
    1  2  3  4  5  6
 7  8  9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31

請輸入想要查看的月份: 例如:1
>>>>>2
   February 2019
Mo Tu We Th Fr Sa Su
             1  2  3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28

請輸入想要查看的月份: 例如:1
>>>>>11111
請正確輸入月份:(1-12)
請輸入想要查看的月份: 例如:1
>>>>>exit

Process finished with exit code 0

簡單說下區(qū)別院峡,UDP編程兴使,服務(wù)端不需要創(chuàng)建連接等待,直接接收照激;也不需要listen設(shè)置最大連接數(shù)鲫惶。客戶端同樣不需要先創(chuàng)建連接实抡,也就是不需要進行connect()操作,直接發(fā)送數(shù)據(jù)即可欢策。數(shù)據(jù)發(fā)送方式改為sendto()吆寨,需要制定地址,畢竟UDP是非面向連接的踩寇。

TCP是建立可靠連接啄清,并且通信雙方都可以以流的形式發(fā)送數(shù)據(jù)。相對TCP俺孙,UDP則是面向無連接的協(xié)議辣卒。使用UDP協(xié)議時,不需要建立連接睛榄,只需要知道對方的IP地址和端口號荣茫,就可以直接發(fā)數(shù)據(jù)包。但是场靴,能不能到達就不知道了啡莉。雖然用UDP傳輸數(shù)據(jù)不可靠港准,但它的優(yōu)點是和TCP比,速度快咧欣,對于不要求可靠到達的數(shù)據(jù)浅缸,就可以使用UDP協(xié)議。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末魄咕,一起剝皮案震驚了整個濱河市衩椒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌哮兰,老刑警劉巖毛萌,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異奠蹬,居然都是意外死亡朝聋,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進店門囤躁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冀痕,“玉大人,你說我怎么就攤上這事狸演⊙陨撸” “怎么了?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵宵距,是天一觀的道長腊尚。 經(jīng)常有香客問我,道長满哪,這世上最難降的妖魔是什么婿斥? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮哨鸭,結(jié)果婚禮上民宿,老公的妹妹穿的比我還像新娘。我一直安慰自己像鸡,他們只是感情好活鹰,可當我...
    茶點故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著只估,像睡著了一般志群。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蛔钙,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天锌云,我揣著相機與錄音,去河邊找鬼吁脱。 笑死宾抓,一個胖子當著我的面吹牛子漩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播石洗,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼幢泼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了讲衫?” 一聲冷哼從身側(cè)響起缕棵,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎涉兽,沒想到半個月后招驴,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡枷畏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年别厘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拥诡。...
    茶點故事閱讀 38,664評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡触趴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出渴肉,到底是詐尸還是另有隱情冗懦,我是刑警寧澤,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布仇祭,位于F島的核電站披蕉,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏乌奇。R本人自食惡果不足惜没讲,卻給世界環(huán)境...
    茶點故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望礁苗。 院中可真熱鬧爬凑,春花似錦、人聲如沸寂屏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽迁霎。三九已至,卻和暖如春百宇,著一層夾襖步出監(jiān)牢的瞬間考廉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工携御, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留昌粤,地道東北人既绕。 一個月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像涮坐,于是被迫代替她去往敵國和親凄贩。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,554評論 2 349

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

  • 網(wǎng)絡(luò)編程 一.楔子 你現(xiàn)在已經(jīng)學會了寫python代碼,假如你寫了兩個python文件a.py和b.py捷雕,分別去運...
    go以恒閱讀 1,999評論 0 6
  • 網(wǎng)絡(luò)編程 網(wǎng)絡(luò)編程對于很多的初學者來說椒丧,都是很向往的一種編程技能,但是很多的初學者卻因為很長一段時間無法進入網(wǎng)絡(luò)編...
    程序員歐陽閱讀 2,009評論 1 37
  • 個人認為救巷,Goodboy1881先生的TCP /IP 協(xié)議詳解學習博客系列博客是一部非常精彩的學習筆記壶熏,這雖然只是...
    貳零壹柒_fc10閱讀 5,051評論 0 8
  • 1、TCP為什么需要3次握手浦译,4次斷開棒假? “三次握手”的目的是“為了防止已失效的連接請求報文段突然又傳送到了服務(wù)端...
    杰倫哎呦哎呦閱讀 3,473評論 0 6
  • 1. 網(wǎng)絡(luò)概述 1.1 概述 1.1.1什么是網(wǎng)絡(luò)? 早期的計算機都是互相獨立的一套一臺以數(shù)據(jù)運算為主的機器管怠。...
    _寧采臣閱讀 717評論 0 1