第二章中主要介绍了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)客户端,在这里是一种问题。可是当咱们进行网络监控时,须要监控到达某一接口的全部数据包时会故意使用这种客户端。
优秀的加密方法,才能够保证程序与正确的服务器进行通讯。可是当没法作到时,能够使用如下两种方案