// 本文部份内容来自网络html
1. 网络基础知识算法
OSI七层模型与TCP/IP模型对应关系编程
HTTPS与HTTPapi
HTTPS 协议的主要做用能够分为两种:一种是创建一个信息安全通道,来保证数据传输的安全;另外一种就是确认网站的真实性。 HTTPS 和 HTTP 的区别主要以下:数组
SSL(Secure Sockets Layer 安全套接层)及其继任者传输层安全(TransportLayer Security,TLS & Datagram Transport Layer Security,DTLS)是为网络通讯提供安全及数据完整性的一种安全协议。DTLS、TLS与SSL在传输层对网络链接进行加密,DTLS在UDP传输协议之上,而SSL/TLS则在TCP传输协议之上。缓存
通常来讲,HTTPS 主要用途有三个:一是经过证书等信息确认网站的真实性;二是创建加密的信息通道;三是数据内容的完整性。安全
SSL证书保证了网站的惟一性与真实性;服务器
签发证书的 CA 中心会发布一种权威性的电子文档——数字证书,它能够经过加密技术(对称加密与非对称加密)对咱们在网上传输的信息进行加密。网络
当数据包通过无数次路由器转发后会发生数据劫持,黑客将数据劫持后进行篡改,好比植入广告;开启HTTPS后黑客就没法对数据进行篡改,就算真的被篡改了,咱们也能够检测出问题数据结构
TCP报文格式
TCP封装在IP报文中的时候,以下图所示,TCP头紧接着IP头(IPV6有扩展头的时候,则TCP头在扩展头后面),不携带选项(option)的TCP头长为20bytes,携带选项的TCP头最长可到60bytes。
TCP的源端口、目的端口、以及IP层的源IP地址、目的IP地址四元组惟一的标识了一个TCP链接
TCP各字段释义:
TCP源端口(Source Port):16位的源端口其中包含发送方应用程序对应的端口。源端口和源IP地址标示报文发送端的地址。
TCP目的端口(Destination port):16位的目的端口域定义传输的目的。这个端口指明报文接收计算机上的应用程序地址接口。
TCP序列号(SequenceNumber):32位的序列号标识了TCP报文中第一个byte在对应方向的传输中对应的字节序号。当SYN出现,SN=ISN(随机值)单位是byte。好比发送端发送的一个TCP包净荷(不包含TCP头)为12byte,SN为5,则发送端接着发送的下一个数据包的时候,SN应该设置为5+12=17。经过序列号,TCP接收端能够识别出重复接收到的TCP包,从而丢弃重复包,同时对于乱序数据包也能够依靠系列号进行重排序,进而对高层提供有序的数据流。另外若是接收的包中包含SYN或FIN标志位,逻辑上也占用1个byte,应答号需加1。
TCP应答号(Acknowledgment Number简称ACK Number):32位的ACK Number标识了报文发送端指望接收的字节序列。若是设置了ACK控制位,这个值表示一个准备接收的包的序列码,注意是准备接收的包,好比当前接收端接收到一个净荷为12byte的数据包,SN为5,则会回复一个确认收到的数据包,若是这个数据包以前的数据也都已经收到了,这个数据包中的ACK Number则设置为12+5=17,表示以前的数据都已经收到了,准备接受SN=17的数据包。
注:关于TCP序列号和应答号,也能够参考文章:http://blog.csdn.net/a19881029/article/details/38091243/
头长(Header Length):4位包括TCP头大小,指示TCP头的长度,即数据从何处开始。header length字段由4比特构成,最大值为15,单位是32比特,即头长的最大值为15*32 bits = 60bytes,所以上面说携带选项的TCP头长最长为60bytes。
保留(Reserved):4位值域,这些位必须是0。为了未来定义新的用途所保留,其中RFC3540将Reserved字段中的最后一位定义为Nonce标志。后续拥塞控制部分的讲解咱们会简单介绍Nonce标志位。
标志(Code Bits):8位标志位,下面介绍。
窗口大小(Window Size):16位,该值指示了从Ack Number开始还愿意接收多少byte的数据量,也即用来表示当前接收端的接收窗还有多少剩余空间,用于TCP的流量控制。
校验位(Checksum):16位TCP头。发送端基于数据内容计算一个数值,接收端要与发送端数值结果彻底同样,才能证实数据的有效性。接收端checksum校验失败的时候会直接丢掉这个数据包。CheckSum是根据伪头+TCP头+TCP数据三部分进行计算的。
优先指针(紧急,Urgent Pointer):16位,指向后面是优先数据的字节,在URG标志设置了时才有效。若是URG标志没有被设置,紧急域做为填充。 选项(Option):长度不定,但长度必须以是32bits的整数倍。常见的选项包括MSS、SACK、Timestamp等等。
八位标志位分别介绍以下:
CWR(Congestion Window Reduce):拥塞窗口减小标志set by sender,用来代表它接收到了设置ECE标志的TCP包。而且sender 在收到消息以后已经经过下降发送窗口的大小来下降发送速率。
ECE(ECN Echo):ECN响应标志被用来在TCP3次握手时代表一个TCP端是具有ECN功能的。在数据传输过程当中也用来代表接收到的TCP包的IP头部的ECN被设置为11。注:IP头部的ECN被设置为11代表网络线路拥堵。
注:关于CWR和ECE标记为详细信息可参考:http://www.cnblogs.com/hadis-yuki/p/5467787.html
URG(Urgent):该标志位置位表示紧急(The urgent pointer) 标志有效。该标志位目前已经不多使用参考后面流量控制和窗口管理部分的介绍。
ACK:取值1表明Acknowledgment Number字段有效,这是一个确认的TCP包,取值0则不是确认包。后续文章介绍中当ACK标志位有效的时候咱们称呼这个包为ACK包,使用大写的ACK称呼。
PSH(Push):该标志置位时,通常是表示发送端缓存中已经没有待发送的数据,接收端不将该数据进行队列处理,而是尽量快将数据转由应用处理。在处理 telnet 或 rlogin 等交互模式的链接时,该标志老是置位的。
RST(Reset):用于reset相应的TCP链接。一般在发生异常或者错误的时候会触发复位TCP链接。
SYN:同步序列编号(Synchronize Sequence Numbers)有效。该标志仅在三次握手创建TCP链接时有效。
FIN(Finish):No more data from sender。当FIN标志有效的时候咱们称呼这个包为FIN包。
UDP报文格式
u2字节源端口字段
源端口是一个大于1023的16位数字,由基于UDP应用程序的用户进程随机选择。
u2字节节的端口字段
u2字节长度字段
指明了包括首部在内的UDP报文段长度。UDP长字段的值是UDP报文头的长度(8字节)与UDP所携带数据长度的总和。
u2字节校验和字段
是指整个UDP报文头和UDP所带的数据的校验和(也包括伪报文头)。伪报文头不包括在真正的UDP报文头中,可是它能够保证UDP数据被正确的主机收到了。因在校验和中加入了伪头标,故ICMP除能防止单纯数据差错以外,对IP分组也具备保护做用。
源端口号和目的端口号如上和TCP的相同。
UDP长度:UDP报文的字节长度(包括首部和数据)。
UDP校验和: 检验UDP首部和数据部分的正确性。
IP报文格式
版本:指IP协议的版本。
首部长度:首部的长度
服务类型:以下图:
其中优先级用来区别优先级别不一样的IP报文。 D表示要求有更低的时延。 T表示要求有更高的吞吐量。 R表示要求有更高的可靠性。
总长度:报文的长度。
标识:因为数据报长度超过传输网络的MTU(最大传输单元)而必须分片,这个标识字段的值被复制到全部数据报分片的标识字段中,使得这些分片在达到最终的目的地时能够依照标识字段的内容从新组成原先的数据报。
标志:最低位是MF,MF=1时,表示后面还有分片。中间位的DF,DF=1时,表示不能分片。
片偏移: 和前面的数据分片相关,是本分片在原先数据报文中相对首位的偏移位。
生存时间:数据报在网络中存活的时间,所容许经过的路由器的最大数量,没经过一个路由器,该值自动减一,若是数值为0,路由器就能够把该数据报丢弃。
协议: 指出数据报携带的数据是使用何种协议,以便目的主机的IP层能知道次数据报上交到哪个进程(不一样协议有一个专门不一样的进程处理)。
首部校验位和:对首部进行校验运算。校验方法 : 在发送端,将IP数据报首部划分为多个16位的二进制序列,并将首部校验和字段置为0,用反码运算将全部16位序列对位相加后,将获得多的 和的反码写入首部校验和字段。接收端接收到数据报后,将数据报首部的全部字段组织成多个16位的二进制序列,再使用反码运算相加 一次,将获得的结果取反。若是结果为0表明没出错,不然出错。
源地址:发送数据报的节点地址。
目的地址:接受数据报的节点地址。
ICMP协议
ICMP是网络层的补充,能够回送报文。用来检测网络是否通畅Ping命令就是发送ICMP的echo包,经过回送的echo relay进行网络测试。
一台拥有IP地址的主机能够提供许多服务,好比Web服务、FTP服务、SMTP服务等,这些服务彻底能够经过1个IP地址来实现。那么,主机是怎样区分不一样的网络服务呢?显然不能只靠IP地址,由于IP 地址与网络服务的关系是一对多的关系。其实是经过"IP地址+端口号"来区分不一样的服务的。
服务器通常都是经过知名端口号来识别的,如图2-2所示。例如,对于每一个TCP/IP实现来讲,FTP服务器的TCP端口号都是21,每一个Telnet服务器的TCP端口号都是23,每一个TFTP(简单文件传送协议)服务器的UDP端口号都是69。任何TCP/IP实现所提供的服务都用知名的1~1023之间的端口号。这些知名端口号由Internet号分配机构(Internet Assigned Numbers Authority,IANA)来管理。
常见的应用层协议和传输层协议之间的关系:
Socket套接字接口参数
sock_stream 是有保障的(即能保证数据正确传送到对方)面向链接的SOCKET,多用于资料(如文件)传送。
sock_dgram 是无保障的面向消息的socket , 主要用于在网络上发广播信息。
SOCK_STREAM是基于TCP的,数据传输比较有保障。SOCK_DGRAM是基于UDP的,专门用于局域网,基于广播SOCK_STREAM
是数据流,通常是tcp/ip协议的编程,SOCK_DGRAM分是数据抱,是udp协议网络编程
AF_INET(又称 PF_INET)是 IPv4 网络协议的套接字类型,AF_INET6 则是 IPv6 的;而 AF_UNIX 则是 Unix 系统本地通讯。
选择 AF_INET 的目的就是使用 IPv4 进行通讯。由于 IPv4 使用 32 位地址,相比 IPv6 的 128 位来讲,计算更快,便于用于局域网通讯。
并且 AF_INET 相比 AF_UNIX 更具通用性,由于 Windows 上有 AF_INET 而没有 AF_UNIX。
AF 表示ADDRESS FAMILY 地址族
PF 表示PROTOCL FAMILY 协议族
TCP三次握手
TCP是主机对主机层的传输控制协议,提供可靠的链接服务,采用三次握手确认创建一个链接:位码即tcp标志位,有6种标示:SYN(synchronous创建联机) ACK(acknowledgement 确认) PSH(push传送) FIN(finish结束) RST(reset重置) URG(urgent紧急)Sequence number(顺序号码) Acknowledge number(确认号码)第一次握手:主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由SYN=1知道,A要求创建联机;第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1,随机产生seq=7654321的包;第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则链接创建成功。
ARP MAC地址解析
数据包常常经过以太网发送,在发送数据包的过程当中先封装IP的帧头信息而后再封装链路层的MAC地址,最后是以太网的帧头信息。以太网的帧头包括:目标地址、源地址、帧的类型,以太网设备的地址是48位的,它不识别32位的IP地址(IPV4)只识别MAC地址。由于以太网只识别设备的MAC地址,那么问题就来了,源地址咱们是知道的就是主机A的MAC地址,那目标的MAC地址呢?咱们可能知道也可能不知道。怎样获得目标的MAC地址呢?地址解析协议会完成IP地址和MAC地址之间的映射获得主机B的MAC地址,这是地址解析协议的绝活。
首先主机A根据路由表的内容肯定B主机的IP地址,而后在本主机上查询ARP缓存的ARP表看看有没有和B主机IP地址对应的MAC地址的历史记录,若是有就添加到以太网帧头的目标地址。若是在ARP表中没有与B主机IP对应的MAC地址,主机A就会向本地网络中的全部主机广播发送ARP请求帧(包含B主机的IP地址,A主机的IP地址和MAC地址),接收到ARP请求的各主机将收到的请求帧中的目标IP地址比较,若是与本身的IP地址不匹配丢弃ARP请求,若是B主机匹配B主机将本身的IP地址和MAC地址回复给发送请求的A主机,同时B主机在ARP表中更新或者记录主机A的IP地址和MAC地址。
A主机在收到数据时首先判断帧的类型,能够看到收到的数据多是IP数据也多是ARP数据。若是收到的是IP数据就会按IP的数据帧格式进行解算,若是收到的是ARP数据帧再判断是响应帧仍是请求帧,若是是响应帧A主机就会更新本地的ARP表,如果请求帧就会把A主机的IP地址和MAC地址回复给发送请求的主机
2. Zephry网络架构
Zephyr经过合并Contiki RTOS开发了一个原生的、优化过的轻量级TCP/IP协议栈(名为uIP,它实现了RFC兼容的IPv四、IPv六、TCP和UDP)。此外,Zephyr还包括一个完整的蓝牙低功耗控制器和一个基于TinyCrypt的加密库,以及支持MQTT和SSL。
######### http ############## ============================ http_client_send_req http_request http_send_flush http_send_msg_raw ######### net context ####### ============================== net_app_send_pkt ctx->send_data net_context_sendto sendto send_data ######### tcp/udp ####### ============================== net_tcp_send_head net_tcp_send_pkt ######### ip ####### ============================== net_send_data net_if_send_data iface->l2->send ######### l2(netif) ####### ============================== dummy_send net_if_queue_tx k_fifo_put(&iface->tx_queue, pkt) net_if_tx(k_fifo_get(&iface->tx_queue, K_NO_WAIT);) api->send xxx_tx(mdm) xxx_send_data xxx_msg_send_ceaselessly xxx_netif_msg_send ######### phy ####### ============================== icp_channel_send
net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, &context);
用于建立socket,信息保存在 struct net_context context 中
绑定本地端口(也可指定绑定IP)
net_context_bind(context, (struct sockaddr *)&my_addr6);
设置接收数据包接口
net_context_recv(context, udp_received, 0, &users_data);
指定接收函数为udp_received,用户提供。当收到外部发送来的数据包时,匹配IP及端口号后,内核从接收线程中调用udp_received。用户根据不一样状况可有两种选择,当数据业务简单且无阻塞操做时,可直接在接收线程中完成对数据包的解析工做。当数据业务复杂或者解析时有阻塞操做时,则应该将数据包传递给应用线程去作,该回调仅仅做为数据传递使用。传递数据包可参考使用全局变量、内核提供的链表、fifo、mailbox、ringbuffer等,也可用户自行决定方式。
获取发送数据包
send_pkt = net_pkt_get_tx(context, K_FOREVER);
获取数据包管理结构
net_pkt_get_data
获取数据data
net_pkt_append_all(send_pkt, expecting_len, data,K_FOREVER);
将数据data拷贝到数据包中struct net_pkt * send_pkt中
net_context_sendto(send_pkt, &dst_addr,addrlen, udp_sent, 0, len, proto);
释放socket
net_context_put(context);
struct net_context *context;
net_context_get(AF_INET, SOCK_STREAM, IPPROTO_TCP,tcp_recv4);
用于建立socket,信息保存在 struct net_context tcp_recv4中
绑定本地端口和IP
net_context_bind(*tcp_recv4,(struct sockaddr *)&my_addr4, sizeof(struct sockaddr_in));
调用tcp链接接口
net_context_connect(tcp_send,(struct sockaddr *)&peer_addr4,
sizeof(peer_addr4),tcp_connected,K_FOREVER,UINT_TO_POINTER(AF_INET));
若链接成功,内核会返回成功值并调用tcp_connected接口通知已经建链。
设置接收数据包接口
net_context_recv(tcp, cb, 0, user_data);
在net_context_connect成功后调用,推荐在tcp_connected中设置。原理同4.3.
获取发送数据包
send_pkt = net_pkt_get_tx(context, K_FOREVER);
获取数据包管理结构
send_frag = net_pkt_get_data(context, K_FOREVER);
获取数据data
net_pkt_frag_add(send_pkt, send_frag);
将数据data信息插入pkt
net_pkt_append_all(send_pkt, expecting_len, data,K_FOREVER);
将数据data拷贝到数据包中struct net_pkt * send_pkt中
发送数据包接口
net_context_send(send_pkt, tcp_sent, 0, len, proto);
释放socket
net_context_put(context);
net_pkt_get_data最终调用内存管理接口申请内存:
net_pkt_get_data _pkt_get_data net_pkt_get_reserve_data net_pkt_get_reserve_data net_buf_alloc net_buf_alloc_len data_alloc pool->alloc->cb->alloc(buf, size, timeout) heap_data_alloc #define net_buf_alloc(_pool, _timeout) net_buf_alloc_len(_pool, CONFIG_NET_BUF_DATA_SIZE ,_timeout); #define CONFIG_NET_BUF_DATA_SIZE 128 也就是说,每次申请数据data的buffer都是固定128字节大小
net_pkt_append_all net_pkt_append net_pkt_append_bytes static inline u16_t net_pkt_append_bytes(struct net_pkt *pkt, const u8_t *value, u16_t len, s32_t timeout) { struct net_buf *frag = net_buf_frag_last(pkt->frags); u16_t added_len = 0; do { u16_t count = min(len, net_buf_tailroom(frag)); void *data = net_buf_add(frag, count); memcpy(data, value, count); len -= count; added_len += count; value += count; if (len == 0) { return added_len; } frag = net_pkt_get_frag(pkt, timeout); if (!frag) { return added_len; } net_pkt_frag_add(pkt, frag); } while (1); /* Unreachable */ return 0; }
net_context_connect:完成TCP三次握手,最终创建链接
1.net_tcp_register注册接收到ack包后的回调接口
ret = net_tcp_register(addr,
laddr,
ntohs(rport),
ntohs(lport),
tcp_synack_received,
context,
&context->conn_handler);
2. 发送syn包
send_syn(context, addr);
3. 收到ack包后进入tcp_synack_received函数,该函数首先注册收到数据后的回调接口tcp_established,而后发送ack包
ret = net_tcp_register(&remote_addr,
&local_addr,
ntohs(tcp_hdr->src_port),
ntohs(tcp_hdr->dst_port),
tcp_established,
context,
&context->conn_handler);
send_ack(context, &remote_addr, false);
相关配置
socket相关的总链接个数(TCP+UDP+ICMP等链接总个数):
CONFIG_NET_MAX_CONN TCPIP链接管理结构体conn个数
CONFIG_NET_MAX_CONTEXTS 对接socket的context个数
说明:如须要修改链接个数,这两个值都要修改,并且个数要一致。Dns功能须要占用一个链接,因此留给客户可以使用的链接个数为“CONFIG_NET_MAX_CONTEXTS-1”。
POLL个数:
CONFIG_NET_SOCKETS_POLL_MAX socket poll的个数,必须大于等于应用用的poll的个数,且不能大于“总链接个数”
TCP服务端链接个数 :
CONFIG_NET_TCP_BACKLOG_SIZE tcp服务端管理数组,必须大于等于tcp当服务端的链接
TCP时间配置
CONFIG_NET_SOCKETS_CONNECT_TIMEOUT tcp链接超时时间,单位秒。超过该时间tcp握手链接失败
CONFIG_NET_TCP_ACK_TIMEOUT 等待对端ACK的超时时间。用于作服务端发送SYN_ACK后等对端ACK,正常状况关闭过程FIN等待对端ACK。 CONFIG_NET_TCP_INIT_RETRANSMISSION_TIMEOUT tcp首次重传时间,之后重传时间每次会翻倍。修改此值会减少因为网络慢致使的重传次数过多,适用于网络延时大的状况。该值能够经过NV配置,如:“AT+ZNVSET="tcp_retran_time",2000”,表示首次重传时间为2000毫秒,该功能重启生效。
CONFIG_NET_TCP_RETRY_COUNT tcp重传次数,超过该重传次数内核会断开链接
内存使用上限配置相关
CONFIG_NET_PKT_RX_COUNT 接收数据包头缓存个数 决定能够缓存多少个IP包
CONFIG_NET_PKT_TX_COUNT 发送数据包头缓存个数
CONFIG_NET_BUF_RX_COUNT 接收数据包数据段个数 决定能够缓存多少个IP数据包数据段,每一个大小为CONFIG_NET_BUF_DATA_SIZE
CONFIG_NET_BUF_TX_COUNT 发送数据包数据段个数
CONFIG_NET_BUF_DATA_SIZE 每一个数据包数据段的大小 单个IP数据包数据段的大小
修改原则:
发送多包小数据,改大CONFIG_NET_PKT_TX_COUNT;
接收多包小数据,改大CONFIG_NET_PKT_RX_COUNT。
发送少包大数据,改大CONFIG_NET_BUF_TX_COUNT;
接收少包大数据,改大CONFIG_NET_BUF_RX_COUNT。
发送多包大数据,改大CONFIG_NET_PKT_TX_COUNT和CONFIG_NET_BUF_TX_COUNT;
接收大包大数据,改大CONFIG_NET_PKT_RX_COUNT和CONFIG_NET_BUF_RX_COUNT。
改小的状况请以此类推。
高层协议指TCP\UDP之上的协议,有时应用传输数据时,会在底层协议之上加载上层协议,好比http、caop等。有时,高层协议会提供socket封装接口,向用户屏蔽socket层的具体调用实现,不一样的操做系统状况不同,在zephyr中,http接口实现了该类封装,当须要使用socket向外发送数据时,只需调用
http_client_init(&http_ctx, SERVER_ADDR, SERVER_PORT);便可,socket由该接口自动建立并供用户使用。发送数据调http_client_send_req(ctx, &req, NULL, result, sizeof(result),NULL, APP_REQ_TIMEOUT);便可
coap协议并无提供这样的封装接口,须要按标准方式调用。
主要接口函数:
int http_client_init(struct http_ctx *ctx,
const char *server,
u16_t server_port,
struct sockaddr *server_addr,
s32_t timeout);
发送数据前,先经过http_client_init()初始化http client,ctx是当前http连接的上下文;server是字符串形式的服务器ip地址或域名(传入域名时必须保证dns解析可用);server_port是服务器监听的端口;server_addr是struct sockaddr形式的ip地址,能够为NULL,为NULL时将使用server做为服务器地址;timeout是域名解析的超时时间。
int http_client_send_req(struct http_ctx *ctx,
struct http_request *req,
http_response_cb_t cb,
u8_t *response_buf,
size_t response_buf_len,
void *user_data,
s32_t timeout);
使用http_client_send_req()发送数据,ctx是当前http连接的上下文;req是发送请求的具体信息和数据(数据结构见上面的重要结构体);cb是应用接收返回的数据的回调;response_buf是应用接收数据存放的空间,须要应用提早申请好空间;response_buf_len是response_buf的长度;user_data设为NULL;timeout是等待服务器回复的超时时间。注意这里的cb是应用主要处理服务器返回的数据的函数,须要应用根据其业务实现。
int net_app_close(struct net_app_ctx *ctx);
释放http连接,ctx是当前net_app连接的上下文,struct http_ctx中有这个struct net_app_ctx。
Accept、Accept-Charset、Accept-Encoding、Accept-language,这些项直接填到struct http_request 中的header_fields里,应用本身解析所指示的可接受的数据内容、字符集、编码方式、语言等。服务器返回的 status code 直接传给应用,由应用来判断成功仍是失败。对于30一、302等重定向的返回码,由应用来处理
http接口中对Socket的封装 http_client_init net_app_init_tcp_client net_app_init_client _net_app_config_local_ctx setup_ipv4_ctx net_context_get bind_local _net_app_set_net_ctx net_context_bind /* TCP recv callback is set after we have accepted the* connection.*/ http_client_send_req net_app_connect http_request http_prepare_and_send get_net_pkt net_app_get_net_pkt_with_dst net_pkt_get_tx net_pkt_append net_pkt_get_frag net_pkt_get_reserve_data net_pkt_frag_add
TLS 创建于TCP可靠的传输机制之上,而DTLS基于UDP,必须自建保障机制: DTLS 必须检测MTU大小,当应用层数据包超过期报错; 为防止握手的IP数据包超载致使丢失,DTLS 针对握手消息实现fragment处理。
TLS 在传输出错时会中断链接,而DTLS需兼容多种出错场景,出错时每每直接丢弃处理;