一点一滴成长

导航

TCP/IP协议(6):传输层之UDP

一、

UDP用户数据报协议,它是一个无连接的,面向数据报的协议,它不提供可靠性但传输速度比TCP要快。

UDP数据报中的“UDP长度”为两个字节,所以我们要发送的UDP数据最多支持65507大约68K的数据,超过该大小的话需要自己来分割发送。 使用UDP必须关心IP数据报的长度,因为如果它超过MTU的话,会对IP数据报进行分片。

在UDP数据报文中,头部占8个字节,报文具体格式如下:


UDP适合一次只传送少量数据、对可靠性要求不高的场景:
  发送小尺寸的数据,如DNS通讯使用的是UDP以提高通信速度。
  流媒体、VOD、IPTV、音视频通讯等常采用UDP。
  UDP的高级应用:广播/多播、P2P、TCP over UDP。

 二、广播/多播

1、

  利用广播可以将数据发送到子网内所有计算机上,广播几乎占用了子网内网络的所有带宽,所以如果有多个进程来同时发送广播数据则网络会阻塞。路由器会隔绝广播。

  对于广播发送方需额外设置两点:一个是设置套接字的SO_BROADCAST选项(BOOL bBroadcast = TRUE; setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char*)&bBroadcast, sizeof(BOOL));),一个是发送数据的地址设为"255.255.255.255",其它按照UDP发送方模型来编程即可。

  对于广播数据接收方按照UDP接收者模型来编程即可接收广播数据。

2、

  多播地址即代表了一个组,用户可以加入或退出这个组,多播地址使用D类IP地址,范围是从224.0.0.0到239.255.255.255,而且有一些地址是保留作为特殊的地址所使用。网络中的交换机和路由器只向加入多播组的主机复制并转发数据,这样可以不影响其他不需要(未加入组)的主机的其他通讯。

  多播编程方法与UDP模型也大体相同,对于发送端需要增加设置数据的TTL生存时间功能(使用函数setsockopt),对于接收端需要增加加入多播组的功能(使用函数setsockopt)。

  多播需要网络硬件(如路由器)的支持或者硬件开启了多播服务。

3、

  单播是主机之间一对一的通讯模式,可以使用TCP或UDP,网络中的交换机和路由器对数据只进行转发不进行复制。网络上大部分的数据都是以单播的形式传输的,如浏览网页、收发邮件等。对于广播或多播数据,网络中的交换机和路由器会对其进行复制并转发。

  广播和多播一般只适合向不同客户传送相同数据的应用,如有线电视使用广播,网络电台使用多播,如果需要对每个客户的不同请求发送不同的数据的话只能使用单播服务器。因为广播和多播是仅发送一次数据所有的接收方就都能收到数据,所以发送方(服务器)流量负载很低,而单播服务器要向所有客户发送数据,即发送多次数据才能到达多个客户上,所以服务器网络负载大。

  因为广播和多播使用的是UDP,发生丢包错包后无法重传。

三、P2P

  NAT使只能内网中计算机去连接外网,然后二者再进行通信,而外网中的计算机是无法主动连接内网计算机进行通信的,所以产生了P2P通信技术来解决这个问题,P2P也被称为NAT打洞或NAT穿透。P2P技术广泛存在于基于UDP的应用中,但本质上,相同的技术也应该支持TCP。

  NAT打洞需要一个处于公网的中间服务器,具体流程为:

  ① A请求Server(向Server发送本地IP地址和端口号的信息, A所处的NAT外网地址Server可以通过recvfrom()的sockaddr_in结构获得),B请求Server。

  ② Server将A的IP地址信息(内网IP+端口,外网IP+端口)发送给B,将B的IP地址信息也发送给A。

  ③ A使用B的外网IP地址和端口号向其发消息,虽然B是收不到消息的(B所在的NAT会将其过滤掉),但这样做只是为了使A信任B,以后B向A发消息A就会收到(A的NAT不会过滤掉,因为A向B主动发过消息就代表A或者说A的NAT信任了B)。

  ④ B使用A的外网IP地址和端口号向其发消息,A会收到,而且这样使B也信任了A。

  ⑤ A和B互相信任,可以直接进行通信了。

  上面的第③步其实还应该向B的内网地址和端口号发消息,以对应处理A和B在一个内网中的情况,具体的步骤可以参考作者休耕的这篇文章:https://www.cnblogs.com/xiugeng/p/12029388.html,这篇文章还介绍了打的洞会出现超时失效问题的解决以及基于TCP协议的P2P打洞技术,以下为截取的该文章的内容:

 

    由于NAT的配置不同,打洞并不保证100%都能成功,所以可以考虑P2P + SSH端口转发的模式。

四、SSH端口转发

  ssh命令除了登陆外还有端口转发(又称代理)的功能,这包括三种转发模式:

    ① 本地端口转发(Local Port Forwarding,又称正向代理)

    ② 远程端口转发(Remote Port Forwarding,又称反向代理)

    ③ 动态端口转发(Dynamic Port Forwarding,又称socks5 代理)

  本地端口转发:将发送到本地端口的请求,转发到目标端口,格式为 -L 本地网卡地址:本地端口:目标地址:目标端口,其中的本地网卡地址可以省略,表示本机所有网卡。如ssh -L localhost:2000:localhost:3000 root@103.59.22.17 表示将发送到本地主机2000端口的请求转发到主机103.59.22.17的3000端口,ssh -L localhost:2000:192.168.59.100:3000 root@103.59.22.17 则表示将发送到本地2000端口的请求经主机103.59.22.17的转发到其局域网下的192.168.59.100:3000下。网上我看到说是这两种方法的区别是第一种用法本地HostA到跳板机 HostB 的数据是明文的,二种用法一般本地就是 HostA,访问本地的 PortA,数据被 ssh 加密传输给 HostB 又转发给 HostC:PortC。

  远程端口转发:将发送到远程端口的请求,转发到目标端口,格式为-R 远程网卡地址:远程端口:目标地址:目标端口,其中的远程网卡地址可以省略,使用时需修改远程主机的 /etc/ssh/sshd_config,添加GatewayPorts yes。如ssh -R :2000:localhost:3000 root@103.59.22.17表示将发送到103.59.22.17主机2000端口上的数据转发到本机的2000端口上,ssh -R :2000:192.168.0.100:3000 root@103.59.22.17则表示将发送到103.59.22.17主机2000端口上的数据转发到本机局域网下192.168.0.100的2000端口上。

  动态端口转发:又称本地 socks5 代理,如ssh -D localhost:1080  HostB 表示本地 1080 端口启动一个 socks5 服务,通过这个 socks5 代理,数据会通过 ssh 链接先发送给 HostB,再从 HostB 转发送给远程目标主机。

  如要长期高效的转发(代理)服务,推荐使用对应的专用软件,ssh-L可以用 iptable 的 port-forwarding 模拟,iptable 性能更好,但是需要 root 权限。ssh-R功能的专业软件有 frp /ngrok /shootback。

五、TCP中的反向链接

  如下的A电脑处于局域网内,NAT为其分配的IP为10.0.0.1,A可以主动连接B电脑,因为B处于公网中,但B不能主动连接A。所以如果B想要给A发通知的话只能是让A先连上B然后等待B随时发来的消息,如果我们只想在有消息的时候A和B再进行连接通信的话可以使用中间的Server电脑 ,让A一直与处于公网的Server相连,当B想要与A通信的时候给Server发一个消息,让Server通知A去连接B。

  

六、TCP over UDP

  TCP over UDP具有UDP速度快、实时性高的特点,同时又兼备TCP的可靠性,它主要是在UDP之上参考TCP协议算法来实现。

七、MQTT与CoAP

  MQTT是一种支持发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,基于TCP(有基于UDP版本的MQTT-SN),由于其低开销,能耗低,且把低带宽、高延迟、不稳定网络等因素考虑在内,所以非常适合智能家居、医疗设备、农业环境监测等小型设备物联网通信。 CoAP也是一种低开销、低带宽占用的即时通讯协议,但其基于UDP,它采用了与HTTP类似的特征,同时又弥补了UDP传输的不可靠性。

posted on 2017-05-27 10:42  整鬼专家  阅读(477)  评论(0编辑  收藏  举报