1. 程式人生 > >《Python網路程式設計基礎》筆記(一)----底層網路

《Python網路程式設計基礎》筆記(一)----底層網路

注:想學點Python。找了本《Python網路程式設計基礎》來學習,用Pydev在MyEclipse搭建好,然後照著書裡的程式碼實踐一番。

作者用的而是2.x版本的,Python2.x和3.x是不相容的,因此要在3.x上跑程式碼,還是要改進一些,順帶了解二者的區別。

一. 客戶端,伺服器網路 1.TCP是一些協議的合集。Internet是在一些共享的線路上傳送資料的。 2.TCP把你要傳送的資料流分解成很多小資訊包在Internet上傳輸。 為了實現這個資訊包的機會,TCP需要 (1)識別遠端機器(IP地址) (2)識別機器的通訊程式(埠號) (3)僅僅為了設計需要/使用者需求(DNS,用DNS替代IP)
3.TCP可靠性的實現: (1)校驗碼 (2)接收方反饋 (3)資訊包附帶序號 4.資訊包的轉發有路由實現 5.資訊的安全有SSL和TLS。提供伺服器的認證,加密,資料完整性 6.伺服器通常是偵聽一個大家都知道的埠號,如Web伺服器偵聽80埠號。MySQL是3306的埠號。如果是自己寫的伺服器程式,服務不屬於有國際因特網地址分配委員會IANA維護的官方埠列表中任一個,則需要選擇一個大於1024,沒有被本機佔用的埠號。最大可以是65535 7.客戶端由作業系統隨機選擇,客戶端程式會選擇一個保證沒有被使用的“短命”的埠號 8.TCP和UDP區別就是UDP不建立連線,只保證資料的完整性,資料傳輸快,但是不保證資料是否真的被收到,也不保證資料是夠只接收一次,也不保證次序。(天,視訊會議用的就是UDP,對網路延遲有很低的容忍度,所以只要我能夠
很快接受到完整的訊息就可以了) UDP:(1)快 不需要花費時間建立和關閉連線      (2)快 偶爾丟失一兩個訊息包無所謂,但是TCP會嚴格檢查      (3)快 UDP的限制是一個資訊包不超過64KB的資料 9.Python網路程式設計 (1)客戶端 Python具有一些協議模組 HTTP FTP 照著程式碼打,可能是因為Python3的原因,str轉換成byte需要encode函式(就是不再支援隱式轉換),解答的連結如下:

In python 3, bytes strings and unicodestrings are now two different types. Since sockets are not aware of string encodings, they are using raw bytes strings, that have a slightly differentinterface from unicode strings.

So, now, whenever you have a unicode stringthat you need to use as a byte string, you need toencode() it. And whenyou have a byte string, you need to decode it to use it as a regular(python 2.x) string.

Unicode strings are quotes enclosedstrings. Bytes strings are b"" enclosed strings

於是在str轉成byte時使用encode()函式,在byte轉換成str時候使用decode()函式,但是quux.org的檔案內容輸出很亂(不是亂碼),不知為何。也許本來如此? 照著人家改,發現最後輸出還是一個樣子,後面把2048改成4096,同樣不行,不理之。截圖:
對於後面的異常捕捉,首先,python2和python3的首要區別就是print不再作為物件而是一個函式,推薦使用這樣的形式:
print("Error connecting to server:{}".format(e))
另外,python3下的except不用逗號,用as

(2)伺服器端
host = ''代表任意連線均可。設定一個port埠號,開啟window中控制面板-程式與功能-開啟或關閉windows功能-勾選telnet客戶端。啟動伺服器,在cmd中輸入“telnet localhost 51423”就可以連上伺服器。輸入字串可以統計輸入字串的字元個數。原文中,按照頡頏劑的修改意見,去掉makefile函式的第二個引數0.

後面的有一個
import gopherlib
看網上資料說從2.6開始就沒有gopherlib這個模組了,所以用不了。
對於urllib,沒有urlopent這個函式,但是urllib.request有,所以
import urllib.request就可以。
另外,gopher://也用不了,直接打個別的網址,如f= urllib.request.urlopen("http://www.python.org")就OK了。截圖:

二.網路客戶端

0. 建立socket物件,連線一個socket,通過socket傳送訊息,等待伺服器處理。

1. 建立socket物件,需要通訊型別和協議家族
Internet通訊,通訊型別基本是AF_INET(IPv4),協議家族:TCP(SOCK_STREAM) UDP:(SOCK_DGRAM)
於是寫成:s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2. 連線一個socket, 首先,提供一個tuple,包括遠端主機名/IP, 埠。另外,在python中,socket物件的connect()函式會根據需要利用DNS把域名自動轉換成IP地址。
s.connect(("www.baidu.com", 80))
4. UDP客戶端和TCP客戶端區別
(1)建立時使用SOCK_DGRAM而不是SOCK_STREAM
(2)埠號是UDP埠號,不是TCP的
(3)沒有辦法檢測伺服器什麼時候傳送完資料,因為這裡沒有實際的連結

三. 網路伺服器

0. 建立socket物件,設定socket選項,繫結到一個埠,偵聽連線
1. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', 80))
s.listen(5) #5表示的是在伺服器實際處理連線時,執行在佇列中等待的連線
2. 通常無限迴圈是不好的,因為它們會耗盡系統的CPU資源。但是這裡有一個accept()函式,它是阻塞的,所以客戶沒有連線成功時不會使用任何資源。
3. 時間戳(返回昨天時間)
伺服器端程式 獲取time.time()時間,處理為昨天時間,打包成二進位制傳送給客戶端

客戶端程式:
發了一個空訊息,然後伺服器就被啟用,傳送時間回來,接收時間是直接recvfrom函式。

執行結果:

4. 伺服器端不能只為一個單一客戶端服務,解決這個問題的方法包括多執行緒技術,另外一個方法是每當有客戶端連線時,啟動一個伺服器的拷貝。這個技術就是使用inetd或者xinetd
5. 死鎖的一個例子程式
伺服器端程式,每次讀取4K程式

客戶端程式:傳送10MB的資料,每次傳送1KB,啟動伺服器之後,啟動客戶端程式,發現程式會在某個時刻停止下來,即讀和寫的兩個程序死鎖。


四. 域名系統

1.域名系統是一個龐大的,全球的分散式的資料庫,遞迴實現將主機名轉成IP地址。這個最大的好處就是大家想上百度的首頁的時候不用打119.75.217.56這麼逆天的地址了(你想想ip多了之後怎麼記),所以“電話簿”DNS域名系統就出來拯救世界了。
另外一個好處可能比較難想到,就是如果百度今天伺服器宕了,換了個IP,難道www.baidu.com就不能登上新的IP?顯然不可能,所以DNS允許伺服器改變IP,但是可以使用相同的名字。
2. 系統先使用hosts檔案來查詢,沒有的話再去DNS查詢。這就是Google不能用了之後,修改hosts強制轉換到某個映象IP的思想了。
3. 正向DNS查詢和逆向DNS查詢
下面的程式碼我嘗試了百度的兩個IP地址 119.75.218.77和119.75.217.56均顯示沒有域名,後面找了網易的www.163.com的地址222.198.122.4(可以CMD,輸入ping www.163.com)也沒有找到。然後無奈之下使用了書裡提供的192.0.34.166居然顯示了。。域名是34-166.lax.icann.org。下面是截圖:

4. 查詢本機資訊

執行結果:IP address的最後一列是自己的Ipv4地址。

5.PyDNS提供了一個功能更強的範文DNS系統的介面]
A記錄:指定某個域名的IP,正向DNS查詢
AAAA記錄:給出一個主機名的IPv6地址
CNAME記錄:定義別名
MX記錄:指定有限選擇的郵件交換伺服器的順序
PTR記錄:指定某個IP的主機名,反向DNS查詢
NS記錄:域名伺服器記錄,指定該域名由那個DNS伺服器進行解析
TXT記錄:儲存關於一個主機的專門資訊
SOA記錄:存有起始授權機構資訊(Start Of Authority)

五. 高階網路操作

1.廣播
還是UDP的操作,但是增加了
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
當接受廣播的所有機器執行伺服器程式,就可以進行廣播接收,這個時候只需要在某個機器上執行傳送程式,所有註冊廣播的機器都將獲取得到廣播的資料和知道廣播機器的IP地址。
伺服器端程式:(最下面是結果 )
客戶端程式及執行結果:

2.IPv4有一個32位的地址空間,理論上可以提供最大為40億的地址。
IPv6有168為的地址空間,理論上可以提供3.40 * 10^38的地址。
早在1979年有一種稱為流協議(ST,ST+,ST2,ST2+)的協議被定義為5
在Python中,IPv6除了建立連線的時候和IPv4不一樣,一旦建立了連線之後就完全一樣了。
下面是測試IP地址的支援情況,我的機子對於www.ipv6.org的分析居然沒有IPv6, 我查了很久,試過幾個方法,結果沒有作用。我連我們學校在我們宿舍樓啟用IPv6有沒有都不清楚,網路中心的人又不回我。。。 但是試了作者的www.ipv5.bieringer.de,居然是這樣的(網站打不開,而且可以確認我的IPv6是不能用的,看能不能開啟http://ipv6.baidu.com/就知道了。)

3.select()的動畫程式
伺服器端程式

客戶端程式:
執行結果: