iOS高级理论:UDP的介绍和使用
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。Socket的英文原义是“孔”或“插座”。作为BSD UNIX的进程通信机制,取后一种意思。通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定
一、Socket简介
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。
Socket的英文原义是“孔”或“插座”。作为BSD UNIX的进程通信机制,取后一种意思。通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。
Socket正如其英文原意那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务。
二、UDP的特点
UDP是是面向非连接的协议,传送数据不需要和服务器连接,只需要知道ip和监听端口,不需要链接没有目的的socket,只是将数据报投递出去,不管接收方是否成功接收到,是一种不可靠的传输。
既然UDP是不可靠数据传输协议,那为什么那么多应用去选择UDP呢?
1、关于何时、发送什么数据的应用层控制更加精细
只要应用将数据传递给UDP,UDP就会将此数据打包进UDP报文段并立刻将其传递给网络层。
而TCP则是有个拥塞控制机制,以确保数据能够安全传输,而不管可靠传输成功需要用多少时间。
所以有些实时应用,比如微信视频、语音都是更希望数据能够及时发送,为此可以容忍一部分数据丢失,比较适合用UDP。
2、无需连接建立
众所周知,TCP在数据传输前需要经过三次握手,UDP却不需要做任何的准备即可进行数据传输,因此UDP不会引入建立连接的时延。
这也是DNS运行在UDP而不是TCP上的主要原因。
而HTTP协议之所以使用TCP,是因为对于HTTP协议来说,可靠性是至关重要的。
3、无连接状态
TCP需要维护连接状态。此连接状态包括接收和发送缓存、拥塞控制参数以及序号与确认号的参数。(后面如果有时间,会详细说下TCP的拥塞控制方案,对该方案来说,这些状态信息都是必要的)
而UDP不需要维护连接状态,也不用跟踪这些参数。
4、分组首部开销小
每个TCP报文段都有20字节的首部开销,而UDP仅有8字节的开销
所以,如非必要,比如电子邮件,远程终端服务,web,以及文件传输,需要可靠地数据传输,会去采用TCP。其余的尤其是对实时性要求高的应用,比如实时视频会议,网络电话,一般都会选用UDP。
三、TCP和UDP的区别
TCP:面向连接、传输可靠(保证数据正确性,保证数据顺序)、用于传输大量数据(流模式)、速度慢,建立连接需要开销较多(时间,系统资源)。
UDP:面向非连接、传输不可靠、用于传输少量数据(数据包模式)、速度快。
区别
关于TCP是一种流模式的协议,UDP是一种数据报模式的协议,这里要说明一下,TCP是面向连接的,也就是说,在连接持续的过程中,socket中收到的数据都是由同一台主机发出的(劫持什么的不考虑),因此,知道保证数据是有序的到达就行了,至于每次读取多少数据自己看着办。
而UDP是无连接的协议,也就是说,只要知道接收端的IP和端口,且网络是可达的,任何主机都可以向接收端发送数据。这时候,如果一次能读取超过一个报文的数据,则会乱套。比如,主机A向发送了报文P1,主机B发送了报文P2,如果能够读取超过一个报文的数据,那么就会将P1和P2的数据合并在了一起,这样的数据是没有意义的。
四、UDP分片发送数据的实现过程
UDP(User Datagram Protocol)是一种无连接的传输协议,它不提供分片和重组的功能。UDP将应用层传递给它的数据报直接封装成UDP数据报,然后通过网络传输。因此,UDP的分片发送数据的实现过程与TCP有所不同。
在UDP中,如果应用层的数据报长度超过了网络的最大传输单元(MTU),UDP将无法自动进行分片。在这种情况下,应用程序需要手动将数据进行分片,并将分片后的数据报发送出去。
UDP分片发送数据的实现过程如下:
-
应用程序将要发送的数据报分为适当大小的片段。片段的大小通常要小于MTU,以确保能够在网络上正确传输。
-
对每个片段进行封装,即在每个片段前添加UDP头部,包括源端口号和目标端口号等信息。
-
将封装后的片段通过网络发送出去。可以使用网络套接字API(如socket)发送UDP数据报。
-
接收方收到UDP数据报后,根据UDP头部的信息进行解封装,获取原始的片段数据。
-
接收方根据片段的顺序和标识信息进行重组,将所有片段按顺序组合成完整的数据报。
需要注意的是,UDP的分片发送是在应用层进行的,而不是在传输层或网络层。因此,UDP分片发送的可靠性和顺序性需要应用程序自己来保证,UDP本身不提供这些功能。
此外,UDP的分片发送可能会导致数据报的丢失或乱序,因为UDP是无连接的,不保证数据的可靠传输。因此,在使用UDP进行分片发送数据时,应用程序需要考虑网络的可靠性和丢包重传等问题,并根据具体的需求选择合适的应用层协议或机制来保证数据的正确传输。
iOS UDP的使用
一、UDP的使用
1.1 引入相关头文件,定义变量
#import "GCDAsyncUdpSocket.h"
@interface UdpManager ()<GCDAsyncUdpSocketDelegate>
{
GCDAsyncUdpSocket *_receiveSocket;
NSString * _destHost;
NSInteger _destPort;
}
1.2 初始化socket,发送数据
初始化 UDP socket ,并绑定端口号和主机IP地址:
- (void)initGCDSocket
{
_destHost = @"127.0.0.1";
_destPort = @"8888";
_receiveSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self
delegateQueue:dispatch_get_global_queue(0, 0)];
NSError *error;
// 绑定一个端口(可选),如果不绑定端口, 那么就会随机产生一个随机的唯一的端口
// 端口数字范围(1024,2^16-1)
[_receiveSocket bindToPort:_destPort error:&error];
if (error) {
NSLog(@"服务器绑定失败");
}
// 开始接收对方发来的消息
[_receiveSocket beginReceiving:nil];
}
1.2 调用socket,发送数据
- (void)sendMessage:(NSString *)message
{
NSData *sendData = [message dataUsingEncoding:NSUTF8StringEncoding];
// 该函数只是启动一次发送 它本身不进行数据的发送, 而是让后台的线程慢慢的发送 也就是说这个函数调用完成后,数据并没有立刻发送,异步发送
[_receiveSocket sendData:sendData toHost:_destHost port:_destPort withTimeout:60 tag:500];
}
1.3 收到消息
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext {
NSString *message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
_destPort = [GCDAsyncUdpSocket portFromAddress:address];
_destHost = [GCDAsyncUdpSocket hostFromAddress:address];
NSLog(@"来自%@---%zd:%@",_destHost,_destPort,message);
}
二、GCDAsyncUdpSocketDelegate 其他的代理方法
//连接成功
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address;
//连接失败
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotConnect:(NSError * _Nullable)error;
//发送数据
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag;
//发送数据报时发生错误(超时或者发送数据太大等)
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError * _Nullable)error;
//接受数据
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
fromAddress:(NSData *)address
withFilterContext:(nullable id)filterContext;
//关闭连接
- (void)udpSocketDidClose:(GCDAsyncUdpSocket *)sock withError:(NSError * _Nullable)error;
更多推荐
所有评论(0)