Dave Python 練習十八 — 網路編程

來源:互聯網
上載者:User

#encoding=utf-8</p><p>###*************** 網路編程 ***************</p><p>#********** Part 1: 通訊端:通訊端點 *******************</p><p>### 1.1 通訊端<br />#通訊端起源於20 世紀70 年代加利福尼亞大學伯克利分校版本的Unix,即人們所說的BSD Unix。<br />#因此,有時人們也把通訊端稱為“伯克利通訊端”或“BSD 通訊端”。一開始,通訊端被設計用在同<br />#一台主機上多個應用程式之間的通訊。這也被稱進程間通訊,或IPC。通訊端有兩種,分別是基於文<br />#件型的和基於網路型的。</p><p>#Unix 通訊端是我們要介紹的第一個通訊端家族。其“家族名”為AF_UNIX(在POSIX1.g 標準中<br />#也叫AF_LOCAL),表示“地址家族:UNIX”。包括Python 在內的大多數流行平台上都使用術語“地址<br />#家族”及其縮寫“AF”。而老一點的系統中,地址家族被稱為“域”或“協議家族”,並使用縮寫“PF”<br />#而不是“AF”。同樣的,AF_LOCAL(在2000-2001 年被列為標準)將會代替AF_UNIX。不過,為了向後<br />#相容,很多系統上,兩者是等價的。Python 自己則仍然使用AF_UNIX。</p><p>#另一種通訊端是基於網路的,它有自己的家族名字:AF_INET,或叫“地址家族:Internet”。<br />#還有一種地址家族AF_INET6 被用於網際協議第6 版(IPv6)定址上。還有一些其它的地址家族,所有地址家族中,AF_INET 是使用最廣泛的一個。<br />#<br />#Python 2.5 中加入了一種Linux 通訊端的支援:AF_NETLINK通訊端家族讓使用者代碼與核心代碼之間的IPC 可以使用標準BSD 套<br />#接字介面。而且,相對之前那些往作業系統中加入新的系統調用,proc 檔案系統支援或是“IOCTL”等笨重的方案來說,這種方法顯得更為優美,更為安全。<br />#<br />#Python 只支援AF_UNIX,AF_NETLINK,和AF_INET 家族。</p><p>## 1.2 通訊端地址:主機與連接埠<br />#如果把通訊端比做電話的插口——即通訊的最底層結構,那主機與連接埠就像區號與電話號碼的<br />#一對組合。有了能打電話的硬體還不夠,你還要知道你要打給誰,往哪打。一個網際網路位址由網<br />#絡通訊所必需的主機與連接埠組成。而且不用說,另一端一定要有人在聽才可以。否則,你就會聽到<br />#熟悉的聲音“對不起,您撥的是空號,請查對後再播”。你在上網的時候,可能也見過類似的情況,<br />#如“不能串連該伺服器。伺服器無響應或不可達”。</p><p>#合法的連接埠號碼範圍為0 到65535。其中,小於1024 的連接埠號碼為系統保留連接埠。如果你所使用的<br />#是Unix 作業系統,保留的連接埠號碼(及其對應的服務/協議和通訊端類型)可以通過/etc/services<br />#檔案獲得。</p><p>## 1.3 連線導向與無串連<br />##1.3.1 連線導向<br />#無論你使用哪一種地址家族。通訊端的類型只有兩種。一種是連線導向的通訊端,即在通訊之<br />#前一定要建立一條串連,就像跟朋友打電話時那樣。這種通訊方式也被稱為“虛電路”或“流套接<br />#字”。連線導向的通訊方式提供了順序的,可靠的,不會重複的資料轉送,而且也不會被加上資料邊<br />#界。這也意味著,每一個要發送的資訊,可能會被拆分成多份,每一份都會不多不少地正確到達目<br />#的地。然後被重新按順序拼裝起來,傳給正在等待的應用程式。<br />#實現這種串連的主要協議就是傳輸控制通訊協定(即TCP)。要建立TCP 通訊端就得在建立的時候,<br />#指定通訊端類型為SOCK_STREAM。TCP 通訊端採用SOCK_STREAM 這個名字,表達了它做為流通訊端的<br />#特點。由於這些通訊端使用網際網路通訊協定 (IP)(IP)來尋找網路中的主機,這樣形成的整個系統,一般<br />#會由這兩個協議(TCP 和IP)來提及,即TCP/IP。</p><p>## 1.3.2 無串連<br />#與虛電路完全相反的是資料報型的無串連通訊端。這意味著,無需建立串連就可以進行通訊。<br />#但這時,資料到達的順序,可靠性及資料不重複性就無法保證了。資料報會保留資料邊界,這就表<br />#示,資料不會像連線導向的協議那樣被拆分成小塊。<br />#使用資料報來傳輸資料就像郵政服務一樣。郵件和包裹不一定會按它們發送的順序到達。事實<br />#上,它們還有可能根本到不了!而且,由於網路的複雜性,資料還可能被重複傳送。<br />#既然資料報有這麼多缺點,為什麼還要使用它呢?由於<br />#連線導向通訊端要提供一些保證,以及要維持虛電路串連,這都是很重的額外負擔。資料報沒有這<br />#些負擔,所以它更“便宜”。通常能提供更好的效能,更適合某些應用場合。</p><p>#實現這種串連的主要協議就是使用者資料包通訊協定(即UDP)。要建立UDP 通訊端就得在建立的時候,<br />#指定通訊端類型為SOCK_DGRAM。SOCK_DGRAM 這個名字,也許你已經猜到了,來自於單詞“datagram”<br />#(“資料報”)。由於這些通訊端使用網際網路通訊協定 (IP)來尋找網路中的主機,這樣形成的整個系統,一<br />#般會由這兩個協議(UDP 和IP)來提及,即UDP/IP。</p><p>#********** Part 2: Python 中的網路編程 *******************<br />## 2.1 socket()模組函數<br />#要使用socket.socket()函數來建立通訊端。其文法如下:<br />#socket(socket_family, socket_type, protocol=0)<br />#socket_family 可以是AF_UNIX 或AF_INET。socket_type 可以是SOCK_STREAM 或SOCK_DGRAM。<br />#這幾個常量的意義可以參考之前的解釋。protocol 一般不填,預設值為0。</p><p>#建立一個TCP/IP 的通訊端,你要這樣調用socket.socket():<br />#tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br />#<br />#同樣地,建立一個UDP/IP 的通訊端,你要這樣:<br />#udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)<br />#<br />#由於socket 模組中有太多的屬性。我們在這裡破例使用了'from module import *'語句。使用<br />#'from socket import *',我們就把socket 模組裡的所有屬性都帶到我們的命名空間裡了,這樣能<br />#大幅減短我們的代碼。<br />#tcpSock = socket(AF_INET, SOCK_STREAM)<br />#當我們建立了通訊端對象後,所有的互動都將通過對該通訊端對象的方法調用進行。</p><p>##2.2 通訊端對象(內建)方法</p><p>#通訊端對象的常用函數<br />#函數 描述<br />####伺服器端通訊端函數<br />#s.bind() 綁定地址(主機,連接埠號碼對)到通訊端<br />#s.listen() 開始TCP 監聽<br />#s.accept() 被動接受TCP 客戶的串連,(阻塞式)等待串連的到來<br />#<br />####用戶端通訊端函數<br />#s.connect() 主動初始化TCP 伺服器串連<br />#s.connect_ex() connect()函數的擴充版本,出錯時返回出錯碼,而不是拋異常<br />#<br />#####公用用途的通訊端函數<br />#s.recv() 接收TCP 資料<br />#s.send() 發送TCP 資料<br />#s.sendall() 完整發送TCP 資料<br />#s.recvfrom() 接收UDP 資料<br />#s.sendto() 發送UDP 資料<br />#s.getpeername() 串連到當前通訊端的遠端的地址<br />#s.getsockname() 當前通訊端的地址<br />#s.getsockopt() 返回指定通訊端的參數<br />#s.setsockopt() 設定指定通訊端的參數<br />#s.close() 關閉通訊端</p><p>####Blocking-Oriented Socket Methods<br />#s.setblocking() 設定通訊端的阻塞與非阻塞模式<br />#s.settimeout() 設定阻塞通訊端操作的逾時時間<br />#s.gettimeout() 得到阻塞通訊端操作的逾時時間<br />#<br />####面向檔案的通訊端的函數<br />#s.fileno() 通訊端的檔案描述符<br />#s.makefile() 建立一個與該通訊端關連的檔案</p><p>#2.3 建立一個TCP 伺服器</p><p>#虛擬碼:<br />#ss = socket() # 建立伺服器通訊端<br />#ss.bind() # 把地址綁定到通訊端上<br />#ss.listen() # 監聽串連<br />#inf_loop: # 伺服器無限迴圈<br />#cs = ss.accept() # 接受客戶的串連<br />#comm_loop: # 通訊迴圈<br />#cs.recv()/cs.send() # 對話(接收與發送)<br />#cs.close() # 關閉客戶通訊端<br />#ss.close() # 關閉伺服器通訊端(可選)</p><p>#所有的通訊端都用socket.socket()函數來建立。伺服器需要“坐在某個連接埠上”等待請求。所<br />#以它們必需要“綁定”到一個本地的地址上。由於TCP 是一個連線導向的通訊系統,在TCP 伺服器<br />#可以開始工作之前,要先完成一些設定。TCP 伺服器必需要“監聽”(進來的)串連,設定完成之後,<br />#伺服器就可以進入無限迴圈了。<br />#<br />#一個簡單的(單線程的)伺服器會調用accept()函數等待串連的到來。預設情況下,accept()<br />#函數是阻塞式的,即程式在串連到來之前會處於掛起狀態。通訊端也支援非阻塞模式。<br />#<br />#一旦接收到一個串連,accept()函數就會返回一個單獨的客戶的通訊端用於後續的通訊。</p><p>#在臨時通訊端建立好之後,通訊就可以開始了。客戶與伺服器都使用這個新建立的通訊端進行<br />#資料的發送與接收,直到通訊的某一方關閉了串連或發送了一個Null 字元串之後,通訊就結束了。</p><p>#在代碼中,當客戶串連關閉後,伺服器繼續等待下一個客戶的串連。代碼的最後一行,會把服<br />#務器的通訊端關閉。由於伺服器處在無限迴圈中,不可能會走到這一步,所以,這一步是可選的。<br />#我們寫這一句話的主要目的是要提醒讀者,在設計一個更智能的退出方案的時候,比方說,伺服器<br />#被通知要關閉的時,要確保close()函數會被調用。</p><p>#樣本:tsTserv.py 建立一個TCP 伺服器程式,當用戶端串連上來之後返回'hello dave'</p><p>#encoding=utf-8</p><p>#from socket import *<br />#from time import ctime<br />#<br />#HOST = '' #HOST 變數為空白,表示bind()函數可以綁定在所有有效地址上。<br />#PORT = 21567<br />#BUFSIZ = 1024 #緩衝的大小設定為1K<br />#ADDR = (HOST, PORT)<br />#<br />#tcpSerSock = socket(AF_INET, SOCK_STREAM)<br />#tcpSerSock.bind(ADDR)<br />#tcpSerSock.listen(5) #最多允許多少個串連同時連進來,後來的串連就會被拒絕掉。<br />#<br />#while True:<br /># print('waiting for connection...')<br /># tcpCliSock, addr = tcpSerSock.accept()<br /># print('...connected from:', addr)<br />#<br /># while True:<br /># data = tcpCliSock.recv(BUFSIZ)<br /># if not data:<br /># break<br /># tcpCliSock.send(b'Hello Dave') #注意在Python 3.x 版本這裡只能send bytes類型<br />#<br />#tcpCliSock.close()<br />#tcpSerSock.close()</p><p>## 2.4 建立TCP 用戶端</p><p>#虛擬碼:<br />#cs = socket() # 建立客戶通訊端<br />#cs.connect() # 嘗試串連伺服器<br />#comm_loop: # 通訊迴圈<br />#cs.send()/cs.recv() # 對話(發送/接收)<br />#cs.close() # 關閉客戶通訊端</p><p>#所有的通訊端都由socket.socket()函數建立。在客戶有了通訊端之後,馬上就可<br />#以調用connect()函數去串連伺服器。串連建立後,就可以與伺服器開始對話了。在對話結束後,客戶就可以關閉通訊端,結束串連。</p><p>#tcTlnt.py 的代碼。程式串連到伺服器,向伺服器發送‘hello world’,伺服器返回‘hello dave’<br />#from socket import *<br />#<br />#HOST = 'localhost' #伺服器的主機名稱與連接埠號碼<br />#PORT = 21567 #連接埠號碼要與伺服器上的設定完全相同<br />#BUFSIZ = 1024<br />#ADDR = (HOST, PORT)<br />#<br />#tcpCliSock = socket(AF_INET, SOCK_STREAM)<br />#tcpCliSock.connect(ADDR)<br />#<br />#while True:<br /># tcpCliSock.send(b'Hello world')<br /># data = tcpCliSock.recv(BUFSIZ)<br />#<br /># if not data:<br /># break<br /># print(data)<br />#<br />#tcpCliSock.close()</p><p>## 2.6 建立一個UDP 伺服器<br />#由於UDP 伺服器不是連線導向的,所以不用像TCP 伺服器那樣做那麼多設定工作。事實上,並不用設定什麼東西,直接等待進來的串連就好了。<br />#ss = socket() # 建立一個伺服器通訊端<br />#ss.bind() # 綁定伺服器通訊端<br />#inf_loop: # 伺服器無限迴圈<br />#cs = ss.recvfrom()/ss.sendto() # 對話(接收與發送)<br />#ss.close() # 關閉伺服器通訊端<br />#<br />#從虛擬碼中可以看出,使用的還是那套先建立通訊端然後綁定到本地地址(主機/連接埠對)的方法。<br />#無限迴圈中包含了從客戶那接收訊息,返回加了時間戳記的結果和回去等下一個訊息這三步。<br />#同樣的,由於代碼不會跳出無限迴圈,所以,close()函數調用是可選的。我們寫這一句話的原因是<br />#要提醒讀者,在設計一個更智能的退出方案的時候,要確保close()函數會被調用。</p><p>##UDP 時間戳記伺服器 (tsUserv.py)</p><p>#from socket import *<br />#from time import ctime<br />#<br />#HOST = ''<br />#PORT = 21567<br />#BUFSIZ = 1024<br />#ADDR = (HOST, PORT)<br />#<br />#udpSerSock = socket(AF_INET, SOCK_DGRAM)<br />#udpSerSock.bind(ADDR)<br />#<br />#while True:<br /># print('waiting for message...')<br /># data, addr = udpSerSock.recvfrom(BUFSIZ)<br /># udpSerSock.sendto(ctime().encode('utf-8'), addr) #這裡注意在Python 3裡sendto 需要用bytes 進行傳送,所以需要使用encode進行轉換<br /># print('...received from and returned to:', addr)<br />#<br />#udpSerSock.close()</p><p>## 2.7 建立一個UDP 用戶端<br />#虛擬碼如下:<br />#cs = socket() # 建立客戶通訊端<br />#comm_loop: # 通訊迴圈<br />#cs.sendto()/cs.recvfrom() # 對話(發送/接收)<br />#cs.close() # 關閉客戶通訊端</p><p>## UDP 用戶端,程式會提示使用者輸入要傳給伺服器的資訊,顯示伺服器返回的加了時間戳記的結果。</p><p>#from socket import *<br />#<br />#HOST = 'localhost'<br />#PORT = 21567<br />#BUFSIZ = 1024<br />#ADDR = (HOST, PORT)<br />#<br />#udpCliSock = socket(AF_INET, SOCK_DGRAM)<br />#<br />#while True:<br /># data = input('> ')<br /># if not data:<br /># break<br /># udpCliSock.sendto(data.encode('utf-8'), ADDR) #這裡注意在Python 3裡sendto 需要用bytes 進行傳送,所以需要使用encode進行轉換<br /># data, ADDR = udpCliSock.recvfrom(BUFSIZ)<br /># if not data:<br /># break<br /># print(data)<br />#<br />#udpCliSock.close()</p><p>#先運行伺服器,在運行用戶端,提示輸入data,然後伺服器返回時間。</p><p>## 2.8 通訊端模組屬性</p><p>#socket 模組屬性<br />#<br />#屬性名稱字 描述<br />#<br />####資料屬性<br />#AF_UNIX, AF_INET, AF_INET6 Python 支援的通訊端家族<br />#SO_STREAM, SO_DGRAM 通訊端類型 (TCP = 流, UDP = 資料報)<br />#has_ipv6 表示是否支援IPv6 的標誌變數<br />#<br />####異常<br />#error 通訊端相關錯誤<br />#herrora 主機和地址相關的錯誤<br />#gaierror 地址相關的錯誤<br />#timeout 逾時<br />#<br />####函數<br />#socket() 用指定的地址家族,通訊端類型和協議類型(可選)建立一個通訊端對象<br />#socketpair() 用指定的地址家族,通訊端類型和協議類型(可選)建立一對通訊端對象<br />#fromfd() 用一個已經開啟的檔案描述符建立一個通訊端對象<br />#<br />####資料屬性<br />#ssl() 在通訊端初始化一個安全通訊端層(SSL)。不做認證驗證。<br />#getaddrinfo() 得到地址資訊<br />#getfqdn() 返回完整的域的名字<br />#gethostname() 得到當前主機名稱<br />#gethostbyname() 由主機名稱得到對應的ip 地址<br />#gethostbyname_ex() gethostbyname()的擴充版本,返回主機名稱,主機所有的別名和IP 位址列表。<br />#gethostbyaddr() 由IP 位址得到DNS 資訊,返回一個類似gethostbyname_ex()的3 元組。<br />#getprotobyname() 由協議名(如'tcp')得到對應的號碼。<br />#getservbyname()/ 由服務名得到對應的連接埠號碼或相反<br />#getservbyport() 兩個函數中,協議名都是可選的。<br />#ntohl()/ntohs() 把一個整數由網路位元組序轉為主機位元組序<br />#htonl()/htons() 把一個整數由主機位元組序轉為網路位元組序<br />#inet_aton()/ 把IP 位址轉為32 位整型,以及反向函數。(僅對IPv4 地址有效)<br />#inet_ntoa()<br />#inet_pton()/ 把IP 位址轉為二進位格式以及反向函數。(僅對IPv4 地址有效)<br />#inet_ntop()<br />#getdefaulttimeout()/ 得到/設定預設的通訊端逾時時間,單位秒(浮點數)<br />#setdefaulttimeout()<br />

-------------------------------------------------------------------------------------------------------
Blog: http://blog.csdn.net/tianlesoftware 
Weibo: http://weibo.com/tianlesoftware
Email: dvd.dba@gmail.com
DBA1 群:62697716(滿);   DBA2 群:62697977(滿)   DBA3 群:62697850(滿)   
DBA 超級群:63306533(滿);  DBA4 群: 83829929(滿)  DBA5群: 142216823(滿)  
DBA6 群:158654907(滿)   DBA7 群:69087192(滿)   DBA8 群:172855474
DBA 超級群2:151508914  DBA9群:102954821      聊天 群:40132017(滿)
--加群需要在備忘說明Oracle資料表空間和資料檔案的關係,否則拒絕申請

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.