笔者最近了解了一下Python相关的内容,发现网络编程部分很是容易可以建立一个UDP本地服务器,正好能够用来分析一下UDP的请求和响应。在本篇文章中,笔者将给你们介绍下IP、UDP的部份内容。html
聊到网络协议,咱们经常会想到OSI(Open System Interconnection 开放式系统互联)七层模型、TCP/IP协议簇,她位于OSI、TCP/IP协议簇哪一层等问题。python
以下图OSI七层模型及对应的TCP/IP协议簇所示。git
下图 是OSI七层模型及对应的TCP/IP 协议簇 github
User Datagram Protocol (UDP)编程
UDP is also a transport-layer protocol and is an alternative to TCP. It provides an unreliable datagram connection between applications. Data is transmitted link by link; there is no end-to-end connection. The service provides no guarantees. Data can be lost or duplicated, and datagrams can arrive out of order.bash
UDP也是传输层协议,是TCP的替代方案。
它在应用程序之间提供不可靠的数据报链接。 数据经过连接传输; 没有端到端的链接。
(这里个人理解是不须要创建链接)该服务不保证可靠传输。 数据可能丢失或重复,数据报可能无序到达。服务器
Internet Protocol (IP)微信
In terms of the OSI model, IP is a network-layer protocol. It provides a datagram service between applications, supporting both TCP and UDP.网络
在OSI模型的中,IP是网络层协议。 它在应用程序之间提供数据报服务,支持TCP和UDP。
笔者在前文提到了要用Python建立一个本地UDP服务器,而且分析UDP的请求及响应过程。这里笔者使用的是PythonIDE、Mac自带的终端简单建立了一个本地UDP服务端和客户端;
请求响应过程为:
-> 启动服务端
-> 启动客户端和服务端创建链接
-> 客户端向服务端发送数据'A'
-> 服务端收到数据向客户端发送'ABCD'。
-> 使用Wireshark对整个请求响应过程进行数据分析。
所用的Python代码以下:
Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 03:13:28)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license()" for more information.
>>> from socketserver import BaseRequestHandler, UDPServer
>>> class handleRequest(BaseRequestHandler):
def handle(self):
print('Got connection from', self.client_address)
msg, sock = self.request
print('RequestMessage:',msg)
resp = 'ABCD'
print('Response:',resp)
sock.sendto(resp.encode('ascii'), self.client_address)
>>> if __name__ == '__main__':
serv = UDPServer(('', 20000), handleRequest)
serv.serve_forever()
复制代码
from socket import socket, AF_INET, SOCK_DGRAM
s = socket(AF_INET, SOCK_DGRAM)
s.sendto('A', ('localhost', 20000))
复制代码
示意图以下:
笔者结合着IP和UDP的首部示意图,及Wireshark的请求及响应进行了以下分析:
在分析数据传输过程以前,笔者先对下边会用到的名词及工具作个简单说明:
字节
即byte
,比特
即bit
,1个字节(byte)=8个比特(bit)。
ASCII码:是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其余西欧语言。它是现今最通用的单字节编码系统。ASCII码对照表
举个例子'A'的ASCII码为0x41 基本的16进制、2进制、10进制之间的转换: -> 16进制0x41 -> 对应2进制为 0100 0001 -> 对应10进制为4 * 16 + 1 = 65 在线进制转换
下图是请求
的示意图,可见数据部分是0x41
表示的是十进制的65,即'A'的ASCII码。
下图是响应
的示意图,可见数据部分是0x41424344
表示的是十进制的65 66 67 68,即'ABCD'的ASCII码。
IP协议所使用的版本
,0100表示的是4即IPv4
IP的首部长度
,0101表示十进制5,不过这里咱们看到Header Length 为20字节,缘由是,Head Length的单位是4字节。(即5 * 4 字节 = 20 字节)。首部长度的最大值为1111即15,首部长度的最大值为15 * 4字节 = 60字节
。
服务类型
部分,优先级标志位和服务类型标志位,被路由器用来进行流量的优先排序。笔者目前不清楚用意,暂不作解释说明。
下图为Total Length(总长度)
显示为001d,16进制的d为13,即13 + 16 = 29。指IP首部和数据报中数据以后的长度,单位为字节。总长度为16位,所以数据报的最大长度为216 - 1 = 65535字节。
标识符
,一个惟一的标识数字,用来识别一个数据报或者被分片数据包的次序。目前笔者对此并不了解,暂不作解释。
下图为标记和分段偏移
。
标记
:用来标识一个数据报是不是一组分片数据包的一部分。
Flags:0x0000
,
1比特
;1比特
;表明不分片;1比特
,MF为0,若是在分片的状况下,表明这是若干分片中的最后一个;分片偏移
为0,占用 13比特
;0 0000 0000 0000分段偏移
:一个数据包是一个分片,这个域中的值就会被用来将数据报以正确顺序从新组装。目前笔者对此并不了解,暂不作解释。
下图为Time to live (存活时间)
,用来定义数据报的生存周期,以通过路由器的条数/秒数 进行秒数。目前笔者对此并不了解,暂不作解释。占用8个比特
,16进制0x40即十进制64。
协议
,用来识别在数据包序列中上层协议数据类型。占用8
个比特,16进制0x11即十进制17。表明UDP。
首部校验和
,一个错误检测机制,用来肯定IP首部的内容有没有被损坏或者篡改。占用16个比特
。
源IP地址
,即发出数据报的主机的IP地址。占用32个比特
。16进制的0x7f表明的127,0x7f00 0001 表示127.0.0.1目的IP地址
,数据报目的地的IP地址。占用32个比特
。16进制的0x7f表明的127,0x7f00 0001 表示127.0.0.1。上述内容就是IP的数据报首部的相关分析,下边笔者将给你们介绍下UDP的首部的相关内容:
UDP的首部
所示,UDP的首部占用 64比特,即8个字节
。UDP的源端口
,占用16比特
。16进制为0x f432
即为十进制的62514
。UDP的目标端口
,占用16比特
。16进制为0x 4e20
即为十进制的20000
。
UDP数据报的字节长度
,表示数据报的字节长度。长度占用UDP首部16比特
。16进制为0x 0009
即为十进制的9
(由于UDP首部长度占8个字节,加上传输了一个数据'A'占用1个字节,共9字节)。UDP数据报的校验和
,用来确保UDP首部和数据到达时的完整性。校验和占用UDP首部16比特
,16进制为0x fe1c
。目前笔者对这个值并不了解,暂不作解释。数据
,包含被UDP封装进去的数据,包含应用层协议头部和用户发出的数据,咱们传输的'A',以下图,显示为16进制的0x41即十进制的65。
小编微信:可加并拉入《QiShare技术交流群》。
关注咱们的途径有:
QiShare(简书)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公众号)
推荐文章:
iOS 多线程之GCD
iOS 多线程之NSOperation
iOS 多线程之NSThread
iOS Winding Rules 缠绕规则
iOS 签名机制
iOS 扫描二维码/条形码
奇舞周刊