日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

第十七章 Python网络编程

發(fā)布時(shí)間:2025/4/5 python 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第十七章 Python网络编程 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Socket簡介

在網(wǎng)絡(luò)上的兩個程序通過一個雙向的通信連接實(shí)現(xiàn)數(shù)據(jù)的交換,這個鏈接的一端稱為一個Socket(套接字),用于描述IP地址和端口。

建立網(wǎng)絡(luò)通信連接至少要一對端口號(Socket),Socket本質(zhì)是編程接口(API),對TCP/IP的封裝,提供了網(wǎng)絡(luò)通信能力。

每種服務(wù)都打開一個Socket,并綁定到端口上,不同的端口對應(yīng)不同的服務(wù),就像http對應(yīng)80端口。

Socket是面向C/S(客戶端/服務(wù)器)模型設(shè)計(jì),客戶端在本地隨機(jī)申請一個唯一的Socket號,服務(wù)器擁有公開的socket,任何客戶端都可以向它發(fā)送連接請求和信息請求。

比如:用手機(jī)打電話給10086客服,你的手機(jī)號就是客戶端,10086客服是服務(wù)端。必須在知道對方電話號碼前提下才能與對方通訊。

Socket數(shù)據(jù)處理流程如圖:

17.1 socket

在Python中提供此服務(wù)的模塊是socket和SocketServer,下面是socket常用的類、方法:

方法描述
socket.socket([family[, type[, proto]]])socket初始化函數(shù),(地址族,socket類型,協(xié)議編號)協(xié)議編號默認(rèn)0
socket.AF_INETIPV4協(xié)議通信
socket.AF_INET6IPV6協(xié)議通信
socket.SOCK_STREAMsocket類型,TCP
socket.SOCK_DGRAMsocket類型,UDP
socket.SOCK_RAW原始socket,可以處理普通socker無法處理的報(bào)文,比如ICMP
socket.SOCK_RDM更可靠的UDP類型,保證對方收到數(shù)據(jù)
socket.SOCK_SEQPACKET可靠的連續(xù)數(shù)據(jù)包服務(wù)

socket.socket()對象有以下方法:

accept()接受連接并返回(socket object, address info),address是客戶端地址
bind(address)綁定socket到本地地址,address是一個雙元素元組(host,port)
listen(backlog)開始接收連接,backlog是最大連接數(shù),默認(rèn)1
connect(address)連接socket到遠(yuǎn)程地址
connect_ex(address)連接socket到遠(yuǎn)程地址,成功返回0,錯誤返回error值
getpeername()返回遠(yuǎn)程端地址(hostaddr, port)
gettimeout()返回當(dāng)前超時(shí)的值,單位秒,如果沒有設(shè)置返回none
recv(buffersize[, flags])接收來自socket的數(shù)據(jù),buffersize是接收數(shù)據(jù)量
send(data[, flags])發(fā)送數(shù)據(jù)到socket,返回值是發(fā)送的字節(jié)數(shù)
sendall(data[, flags])發(fā)送所有數(shù)據(jù)到socket,成功返回none,失敗拋出異常
setblocking(flag)設(shè)置socket為阻塞(flag是true)或非阻塞(flag是flase)

溫習(xí)下TCP與UDP區(qū)別:

TCP和UDP是OSI七層模型中傳輸層提供的協(xié)議,提供可靠端到端的傳輸服務(wù)。

TCP(Transmission Control Protocol,傳輸控制協(xié)議),面向連接協(xié)議,雙方先建立可靠的連接,再發(fā)送數(shù)據(jù)。適用于可靠性要求高的應(yīng)用場景。

UDP(User Data Protocol,用戶數(shù)據(jù)報(bào)協(xié)議),面向非連接協(xié)議,不與對方建立連接,直接將數(shù)據(jù)包發(fā)送給對方,因此相對TCP傳輸速度快?。適用于可靠性要求低的應(yīng)用場景。

17.1.1 TCP編程

下面創(chuàng)建一個服務(wù)端TCP協(xié)議的Socket演示下。

先寫一個服務(wù)端:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #!/usr/bin/python #?-*-?coding:?utf-8?-*- import?socket HOST?=?''?????????????????#?為空代表所有可用的網(wǎng)卡 PORT?=?50007??????????????#?任意非特權(quán)端口 s?=?socket.socket(socket.AF_INET,?socket.SOCK_STREAM) s.bind((HOST,?PORT)) s.listen(1)???#?最大連接數(shù) conn,?addr?=?s.accept()???#?返回客戶端地址 print?'Connected?by',?addr while?1: ????data?=?conn.recv(1024)???#?每次最大接收客戶端發(fā)來數(shù)據(jù)1024字節(jié) ????if?not?data:?break???????#?當(dāng)沒有數(shù)據(jù)就退出死循環(huán)? ????print?"Received:?",?data?#?打印接收的數(shù)據(jù) ????conn.sendall(data)???????#?把接收的數(shù)據(jù)再發(fā)給客戶端 conn.close()

再寫一個客戶端:

1 2 3 4 5 6 7 8 9 10 11 #!/usr/bin/python #?-*-?coding:?utf-8?-*- import?socket HOST?=?'192.168.1.120'????#?遠(yuǎn)程主機(jī)IP PORT?=?50007??????????????#?遠(yuǎn)程主機(jī)端口 s?=?socket.socket(socket.AF_INET,?socket.SOCK_STREAM) s.connect((HOST,?PORT)) s.sendall('Hello,?world')?#?發(fā)送數(shù)據(jù) data?=?s.recv(1024)???????#?接收服務(wù)端發(fā)來的數(shù)據(jù) s.close() print?'Received:?',?data

寫好后,打開一個終端窗口執(zhí)行:

1 2 3 4 5 #?python?socket-server.py 監(jiān)聽中... #?直到客戶端運(yùn)行會接收到下面數(shù)據(jù)并退出 Connected?by?('192.168.1.120',?37548) Received:??Hello,?world

再打開一個終端窗口執(zhí)行:

# 如果端口監(jiān)聽說明服務(wù)端運(yùn)行正常

1 2 3 4 #?netstat?-antp?|grep?50007 tcp????????0??????0?0.0.0.0:50007???????????0.0.0.0:*???????????????LISTEN??????72878/python #?python?socket-client.py Received:?Hello,?world

通過實(shí)驗(yàn)了解搭到Socket服務(wù)端工作有以下幾個步驟:

1)打開socket

2)綁定到一個地址和端口

3)監(jiān)聽進(jìn)來的連接

4)接受連接

5)處理數(shù)據(jù)

17.1.2 UDP編程

服務(wù)端:

1 2 3 4 5 6 7 8 9 10 11 import?socket HOST?=?''??????????????? PORT?=?50007????????????? s?=?socket.socket(socket.AF_INET,?socket.SOCK_DGRAM) s.bind((HOST,?PORT)) while?1: ????data,?addr?=?s.recvfrom(1024) ????print?'Connected?by',?addr ????print?"Received:?",?data ????s.sendto("Hello?%s"%?repr(addr),?addr) conn.close()

客戶端:

1 2 3 4 5 6 7 8 import?socket HOST?=?'192.168.1.99'????????????????? PORT?=?50007????????????? s?=?socket.socket(socket.AF_INET,?socket.SOCK_DGRAM) s.sendto(data,?(HOST,?PORT)) data?=?s.recv(1024) s.close() print?'Received:?',?data

運(yùn)行方式與TCP編程一樣。

使用UDP協(xié)議時(shí),服務(wù)端就少了listen()和accept(),不需要建立連接就直接接收客戶端的數(shù)據(jù),也是把數(shù)據(jù)直接發(fā)送給客戶端。

客戶端少了connect(),同樣直接通過sendto()給服務(wù)器發(fā)數(shù)據(jù)。

而TCP協(xié)議則前提先建立三次握手。

17.1.3 舉一個更直觀的socket通信例子

客戶端發(fā)送bash命令,服務(wù)端接收到并執(zhí)行,把返回結(jié)果回應(yīng)給客戶端。

服務(wù)端:

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 32 33 34 35 36 37 38 39 #!/usr/bin/python #?-*-?coding:?utf-8?-*- import?sys import?subprocess import?socket HOST?=?''??????????????? PORT?=?50007????????????? try: ????s?=?socket.socket(socket.AF_INET,?socket.SOCK_STREAM) ????s.bind((HOST,?PORT)) ????s.listen(1) except?socket.error?as?e: ????s.close() ????print?e ????sys.exit(1) while?1: ????conn,?addr?=?s.accept() ????print?'Connected?by',?addr ????while?1: ????????#?每次讀取1024字節(jié) ????????data?=?conn.recv(1024) ????????if?not?data:?#?客戶端關(guān)閉服務(wù)端會收到一個空數(shù)據(jù) ????????????print?repr(addr)?+?"?close." ????????????conn.close() ????????????break????? ????????print?"Received:?",?data ????????cmd?=?subprocess.Popen(data,?stdout=subprocess.PIPE,?stderr=subprocess.PIPE,?shell=True) ????????result_tuple?=?cmd.communicate() ????????if?cmd.returncode?!=?0?or?cmd.returncode?==?None: ????????????result?=?result_tuple[1] ????????????#?result?=?cmd.stderr.read() ????????else: ????????????result?=?result_tuple[0] ????????????#?result?=?cmd.stdout.read()??#?讀不到標(biāo)準(zhǔn)輸出,不知道為啥,所以不用 ????????if?result: ????????????conn.sendall(result) ????????else: ????????????conn.sendall("return?null") s.close()

客戶端:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #!/usr/bin/python #?-*-?coding:?utf-8?-*- import?sys import?socket HOST?=?'192.168.1.120'??? PORT?=?50007????????????? try: ????s?=?socket.socket(socket.AF_INET,?socket.SOCK_STREAM) ????s.connect((HOST,?PORT)) except?socket.error?as?e: ????s.close() ????print?e ????sys.exit(1) while?1: ????cmd?=?raw_input("Please?input?command:?") ????if?not?cmd:?continue ????s.sendall(cmd) ????recv_data?=?s.recv(1024) ????print?'Received:?',?recv_data s.close()

查看運(yùn)行效果,先運(yùn)行服務(wù)端,再運(yùn)行客戶端:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #?python?socket-server.py Connected?by?('192.168.1.120',?45620) Received:??ls Received:??touch?a.txt Received:??ls #?python?socket-client.py Please?input?command:?ls Received:? socket-client.py socket-server.py Please?input?command:?touch?a.txt Received:??return?null Please?input?command:?ls Received:? a.txt socket-client.py socket-server.py Please?input?command:

我想通過上面這個例子你已經(jīng)大致掌握了socket的通信過程。

再舉一個例子,通過socket獲取本機(jī)網(wǎng)卡IP:

1 2 3 4 5 6 7 8 9 10 >>>?socket.gethostname() 'ubuntu' >>>?socket.gethostbyname(socket.gethostname()) '127.0.1.1' >>>?s?=?socket.socket(socket.AF_INET,?socket.SOCK_DGRAM) >>>?s.connect(('10.255.255.255',?0)) >>>?s.getsockname() ('192.168.1.120',?35765) >>>?s.getsockname()[0] '192.168.1.120'


博客地址:http://lizhenliang.blog.51cto.com

QQ群:323779636(Shell/Python運(yùn)維開發(fā)群)


17.2 SocketServer

ScoketServer是Socket服務(wù)端庫,比socket庫更高級,實(shí)現(xiàn)了多線程和多線程,并發(fā)處理多個客戶端請求。

下面是幾個常用的類:

SocketServer.TCPServer(server_address,?

RequestHandlerClass,?bind_and_activate=True)

服務(wù)器類,TCP協(xié)議

SocketServer.UDPServer(server_address,?

RequestHandlerClass,?bind_and_activate=True)

服務(wù)器類,UDP協(xié)議

SocketServer.BaseServer(server_address,?

RequestHandlerClass)

這個是所有服務(wù)器對象的超類。它定義了接口,不提供大多數(shù)方法,在子類中進(jìn)行。
SocketServer.BaseRequestHandler 這個是所有請求處理對象的超類。它定義了接口,一個具體的請求處理程序子類必須定義一個新的handle()方法。
SocketServer.StreamRequestHandler流式socket,根據(jù)socket生成讀寫socket用的兩個文件對象,調(diào)用rfile和wfile讀寫
SocketServer.DatagramRequestHandler數(shù)據(jù)報(bào)socket,同樣生成rfile和wfile,但UDP不直接關(guān)聯(lián)socket。這里rfile是由UDP中讀取的數(shù)據(jù)生成,wfile則是新建一個StringIO,用于寫數(shù)據(jù)
SocketServer.ForkingMixIn/ThreadingMixIn多進(jìn)程(分叉)/多線程實(shí)現(xiàn)異步。混合類,這個類不會直接實(shí)例化。用于實(shí)現(xiàn)處理多連接

SocketServer.BaseServer()對象有以下方法:

fileno()返回一個整數(shù)文件描述符上服務(wù)器監(jiān)聽的套接字
handle_request()處理一個請求
serve_forever(poll_interval=0.5)處理,直至有明確要求shutdown()的請求。輪訓(xùn)關(guān)機(jī)每poll_interval秒
shutdown()告訴serve_forever()循環(huán)停止并等待
server_close()清理服務(wù)器
address_family地址族
server_address監(jiān)聽的地址
RequestHandlerClass用戶提供的請求處理類
socketsocket對象上的服務(wù)器將監(jiān)聽傳入的請求
allow_reuse_address服務(wù)器是否允許地址的重用。默認(rèn)False
request_queue_size請求隊(duì)列的大小。
socket_typesocket類型。socket.SOCK_STREAM或socket.SOCK_DGRAM
timeout超時(shí)時(shí)間,以秒為單位
finish_request()實(shí)際處理通過實(shí)例請求RequestHandleClass并調(diào)用其handle()方法
get_request()必須接受從socket的請求,并返回
handle_error(request, client_address)如果這個函數(shù)被條用handle()
process_request(request, client_address)?
server_activate()?
server_bind()由服務(wù)器構(gòu)造函數(shù)調(diào)用的套接字綁定到所需的地址
verify_request(request, client_address)返回一個布爾值,如果該值是True,則該請求將被處理,如果是False,該請求將被拒絕。

創(chuàng)建一個服務(wù)器需要幾個步驟:

1)創(chuàng)建類,繼承請求處理類(BaseRequestHandler),并重載其handle()方法,此方法將處理傳入的請求

2)實(shí)例化服務(wù)器類之一,它傳遞服務(wù)器的地址和請求處理程序類

3)調(diào)用handle_request()或serve_forever()服務(wù)器對象的方法來處理一個或多個請求

4)調(diào)用server_close()關(guān)閉套接字

17.2.1 TCP編程

服務(wù)端:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #!/usr/bin/python #?-*-?coding:?utf-8?-* import?SocketServer class?MyTCPHandler(SocketServer.BaseRequestHandler): ????""" ????請求處理程序類。 ????每個連接到服務(wù)器都要實(shí)例化一次,而且必須覆蓋handle()方法來實(shí)現(xiàn)與客戶端通信 ????""" ????def?handle(self): ????????#?self.request?接收客戶端數(shù)據(jù) ????????self.data?=?self.request.recv(1024).strip() ????????print?"%s?wrote:"?%?(self.client_address[0]) ????????print?self.data ????????#?把接收的數(shù)據(jù)轉(zhuǎn)為大寫發(fā)給客戶端 ????????self.request.sendall(self.data.upper()) if?__name__?==?"__main__": ????HOST,?PORT?=?"localhost",?9999 ????#?創(chuàng)建服務(wù)器并綁定本地地址和端口 ????server?=?SocketServer.TCPServer((HOST,?PORT),?MyTCPHandler) ????#?激活服務(wù)器,會一直運(yùn)行,直到Ctrl-C中斷 ????server.serve_forever()

另一個請求處理程序類,利用流(類文件對象簡化通信提供標(biāo)準(zhǔn)文件接口):

1 2 3 4 5 6 7 8 class?MyTCPHandler(SocketServer.StreamRequestHandler): ????def?handle(self): ????????#?self.rfile創(chuàng)建的是一個類文件對象處理程序,就可以調(diào)用readline()而不是recv() ????????self.data?=?self.rfile.readline().strip() ????????print?"%s?wrote:"?%?(self.client_address[0]) ????????print?self.data ????????#?同樣,self.wfile是一個類文件對象,用于回復(fù)客戶端 ????????self.wfile.write(self.data.upper())

客戶端:

1 2 3 4 5 6 7 8 9 10 11 12 13 import?socket import?sys HOST,?PORT?=?"localhost",?9999 data?=?"?".join(sys.argv[1:]) sock?=?socket.socket(socket.AF_INET,?socket.SOCK_STREAM) try: ????sock.connect((HOST,?PORT)) ????sock.sendall(data?+?"\n") ????received?=?sock.recv(1024) finally: ????sock.close() print?"Sent:?%s"?%?data print?"Received:?%s"?%?received

服務(wù)端結(jié)果:

1 2 3 4 5 #?python?TCPServer.py 127.0.0.1?wrote: hello 127.0.0.1?wrote: nice

客戶端結(jié)果:

1 2 3 4 5 6 #?python?TCPClient.py?hello Sent:?hello Received:?HELLO #?python?TCPClient.py?nice Sent:?nice Received:?NICE

17.2.2 UDP編程

服務(wù)端:

1 2 3 4 5 6 7 8 9 10 11 12 import?SocketServer class?MyTCPHandler(SocketServer.BaseRequestHandler): ????def?handle(self): ????????self.data?=?self.request[0].strip() ????????self.socket?=?self.request[1] ????????print?"%s?wrote:"?%?(self.client_address[0]) ????????print?self.data ????????self.socket.sendto(self.data.upper(),?self.client_address) if?__name__?==?"__main__": ????HOST,?PORT?=?"localhost",?9999 ????server?=?SocketServer.UDPServer((HOST,?PORT),?MyTCPHandler) ????server.serve_forever()

客戶端:

1 2 3 4 5 6 7 8 9 import?socket import?sys HOST,?PORT?=?"localhost",?9999 data?=?"?".join(sys.argv[1:]) sock?=?socket.socket(socket.AF_INET,?socket.SOCK_DGRAM) sock.sendto(data?+?"\n",?(HOST,?PORT)) received?=?sock.recv(1024) print?"Sent:?%s"?%?data print?"Received:?%s"?%?received

與TCP執(zhí)行結(jié)果一樣。

17.2.3 異步混合

創(chuàng)建異步處理,使用ThreadingMixIn和ForkingMixIn類。

ThreadingMixIn類的一個例子:

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 32 33 34 35 36 37 38 #!/usr/bin/python #?-*-?coding:?utf-8?-* import?socket import?threading import?SocketServer class?ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler): ????def?handle(self): ????????data?=?self.request.recv(1024) ????????cur_thread?=?threading.current_thread() ????????response?=?"%s:?%s"?%?(cur_thread.name,?data) ????????self.request.sendall(response) class?ThreadedTCPServer(SocketServer.ThreadingMixIn,?SocketServer.TCPServer): ????pass def?client(ip,?port,?message): ????sock?=?socket.socket(socket.AF_INET,?socket.SOCK_STREAM) ????sock.connect((ip,?port)) ????try: ????????sock.sendall(message) ????????response?=?sock.recv(1024) ????????print?"Received:?%s"?%?response ????finally: ????????sock.close() if?__name__?==?"__main__": ????#?端口0意味著隨機(jī)使用一個未使用的端口 ????HOST,?PORT?=?"localhost",?0 ????server?=?ThreadedTCPServer((HOST,?PORT),?ThreadedTCPRequestHandler) ????ip,?port?=?server.server_address ????#?服務(wù)器啟動一個線程,該線程將開始。每個線程處理每個請求 ????server_thread?=?threading.Thread(target=server.serve_forever) ????#?作為守護(hù)線程 ????server_thread.daemon?=?True ????server_thread.start() ????print?"Server?loop?running?in?thread:",?server_thread.name ????client(ip,?port,?"Hello?World?1") ????client(ip,?port,?"Hello?World?2") ????client(ip,?port,?"Hello?World?3") ????server.shutdown() ??????server.server_close()

1 2 3 4 5 #?python?socket-server.py Server?loop?running?in?thread:?Thread-1 Received:?Thread-2:?Hello?World?1 Received:?Thread-3:?Hello?World?2 Received:?Thread-4:?Hello?World?3


本文轉(zhuǎn)自 李振良OK 51CTO博客,原文鏈接:http://blog.51cto.com/lizhenliang/1879549,如需轉(zhuǎn)載請自行聯(lián)系原作者

總結(jié)

以上是生活随笔為你收集整理的第十七章 Python网络编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。