第二章中主要介紹了UDP協議python
UDP是OSI參考模型中一種無鏈接的傳輸層協議,它主要用於不要求分組順序到達的傳輸中,分組傳輸順序的檢查與排序由應用層完成,提供面向事務的簡單不可靠信息傳送服務。UDP 協議基本上是IP協議與上層協議的接口。UDP協議適用端口分別運行在同一臺設備上的多個應用程序。
UDP提供了無鏈接通訊,且不對傳送數據包進行可靠性保證,適合於一次傳輸少許數據,UDP傳輸的可靠性由應用層負責。經常使用的UDP端口號有:
DNS(53) TFTP(69) SNMP(161)
UDP報文沒有可靠性保證、順序保證和流量控制字段等,可靠性較差。可是正由於UDP協議的控制選項較少,在數據傳輸過程當中延遲小、數據傳輸效率高,適合對可靠性要求不高的應用程序,或者能夠保障可靠性的應用程序,如DNS、TFTP、SNMP等。
UDP在IP報文中的位置如圖所示。git
無符號16位數(0-65536)其中知名端口(0-1023)、註冊端口(1024-49151)、其他端口(49152-65535)github
Source(IP:port number) ->Destination(IP:port number)shell
在python中能夠使用socket模塊的getservbyname()函數獲取知名端口名對應的端口號例如編程
import socket
socket.getservbyname('domain') Out[4]: 53 socket.getservbyname('http') Out[5]: 80
在設計網絡編程API時,Python標準庫在底層對兼容POSIX操做系統(注:可移植操做系統接口(Portable Operating System Interface of UNIX,縮寫爲 POSIX ),如LInux和MacOS)網絡操做的底層系統調用進行了封裝,並未全部普通的原始調用提供了一個簡單的基於對象的系統。封裝後的Python函數名與原始系統調用名相同。Python的這種設計使開發者能夠使用早已熟知的方法來調用傳統系統。windows
不管對於WIndows仍是POSIX系統,網絡操做背後的系統調用鬥神圍繞着套接字(Socket)這一律念進行的。服務器
套接字是一個通訊端點,操做系統使用整數標識套接字,而Python使用socket.socket對象來更方便的表示套接字,該對象內部維護了操做系統標識套接字的整數(能夠調用它的fileno()方法來查看),每當調用socket.socket對象的方法請求使用該套接字的系統調用時,該對象都會自動使用內部維護的套接字整數標識符。網絡
根據書上的代碼,咱們能夠創建一個簡單的UDP客戶端dom
#!/usr/bin/env python3 # Foundations of Python Network Programming, Third Edition # https://github.com/brandon-rhodes/fopnp/blob/m/py3/chapter02/udp_local.py # UDP client and server on localhost import argparse, socket from datetime import datetime MAX_BYTES = 65535 def server(port): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind(('127.0.0.1', port)) print('Listening at {}'.format(sock.getsockname())) while True: data, address = sock.recvfrom(MAX_BYTES) text = data.decode('ascii') print('The client at {} says {!r}'.format(address, text)) text = 'Your data was {} bytes long'.format(len(data)) data = text.encode('ascii') sock.sendto(data, address) def client(port): sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) text = 'The time is {}'.format(datetime.now()) data = text.encode('ascii') sock.sendto(data, ('127.0.0.1', port)) print('The OS assigned me the address {}'.format(sock.getsockname())) data, address = sock.recvfrom(MAX_BYTES) # Danger! See Chapter 2 text = data.decode('ascii') print('The server {} replied {!r}'.format(address, text)) if __name__ == '__main__': choices = {'client': client, 'server': server} parser = argparse.ArgumentParser(description='Send and receive UDP locally') parser.add_argument('role', choices=choices, help='which role to play') parser.add_argument('-p', metavar='PORT', type=int, default=1060, help='UDP port (default 1060)') args = parser.parse_args() function = choices[args.role] function(args.p)
使用powshell(Windows下(目錄有空格轉義竟然是用`,試了\半天0.0)定位到當前目錄socket
輸入
python udp_local.py server #udp_local.py是本文件名
固然若是端口被佔用(例如本例子中的1060)會提示
Traceback (most recent call last): File "udp_local.py", line 44, in <module> function(args.p) File "udp_local.py", line 14, in server sock.bind(('127.0.0.1', port)) OSError: [WinError 10048] 一般每一個套接字地址(協議/網絡地址/端口)只容許使用一次。
以後再打開一個shell定位到當前頁面輸入
python udp_local.py client
會顯示
The OS assigned me the address ('0.0.0.0', 59457) The server ('127.0.0.1', 1060) replied 'Your data was 38 bytes long'
而server窗口同時顯示
The client at ('127.0.0.1', 59457) says 'The time is 2018-01-15 16:24:19.498818'
而若是server已關閉本條指令會在powershell顯示
The OS assigned me the address ('0.0.0.0', 50859) Traceback (most recent call last): File "udp_local.py", line 44, in <module> function(args.p) File "udp_local.py", line 31, in client data, address = sock.recvfrom(MAX_BYTES) # Danger! See Chapter 2 ConnectionResetError: [WinError 10054] 遠程主機強迫關閉了一個現有的鏈接。
程序中使用了sock.sendto()函數(須要指定地址和端口)
使用了sock.getsockname()調用查看IP地址和端口號,在輸出中咱們能夠看出在這裏分配的是59457端口
從上面的程序中咱們也能明顯看出,這樣的程序其實是至關危險的,在客戶端等待服務器的響應時(在windows下能夠經過發送響應中添加time.sleep()實現)咱們能夠向客戶端程序發送一個‘僞造的信息’,如
>>>import socket >>>sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) >>>sock.sendto('FAKE'.encode('ascii'),('127.0.0.1',59457))
客戶端會當即結束等待,並將此響應看爲服務器的響應
像這樣不考慮地址是否正確,接受並處理全部收到的數據包的網絡監聽客戶端在技術上叫作混雜(promiscuous)客戶端,在這裏是一種問題。可是當咱們進行網絡監控時,須要監控到達某一接口的全部數據包時會故意使用這種客戶端。
優秀的加密方法,才能夠保證程序與正確的服務器進行通訊。可是當沒法作到時,能夠使用如下兩種方案