UDP | TCP | |
---|---|---|
是否需连接 | 无连接 | 面向连接 |
是否可靠性 | 传输可靠性不保证 | 可靠传输 |
连接方式 | 单播,广播,任播 | 单播 |
数据传输方式 | 报文 | 字节流 |
是否拥塞控制 | 不使用 | 支持拥塞控制 |
是否流量控制 | 不使用 | 支持流量控制 |
报文开销 | 8字节 | 20~60字节 |
数据传输方式
1、UDP 报文(数据报)
UDP传输时,UDP模块就将应用层下发到传输层的数据封装成一个数据报并直接发送。接收端必须及时对每个udp数据报执行读操作并且一次接受完,否则不读数据会丢包,或者不读完整数据会被截断发生数据丢失都是保证将一个个报文独立地传输。
UDP传输方式如下图所示
2、TCP 字节流
当数据到传输层封装成报文后,Tcp会根据双方定义的窗口尺寸,将报文进行分割或者粘结,保证传输的数据不超过窗口容量限制,进行发送,这样就可能将报文进行分裂,无法保证信息完整的报文头尾边界。
应用程序对数据的发送和接受没有边界限制,即发送端执行的写操作次数和接受端的读操作次数没有任何数量关系,并且send只是将数据写进发送缓冲区,recv只是从输出缓冲区中获取数据。
TCP传输方式如下图所示
拥塞控制
1、UDP
UDP没有流量控制和拥塞控制,所以在网络拥塞时不会降低发送方的发送速率
2、TCP
当网络出现拥塞的时候,TCP能减小向网络注入数据的速率和数量,缓解拥塞,并将丢失数据进行重发。
TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。
流量控制
1、UDP
UDP没有流量控制和拥塞控制,所以在网络拥塞时不会降低发送方的发送速率
2、TCP
TCP中采用滑动窗口来进行流量控制,滑动窗口的大小意味着接收方还有多大的缓冲区可以用于接收数据。发送方可以通过滑动窗口的大小来确定应该发送多少字节的数据。当滑动窗口为0时,发送方一般不能再发送数据报。
滑动窗口协议的基本原理就是在任意时刻,发送方都维持了一个连续的允许发送的帧的序号,称为发送窗口;同时,接收方也维持了一个连续的允许接收的帧的序号,称为接收窗口。发送窗口和接收窗口的序号的上下界不一定要一样,甚至大小也可以不同。不同的滑动窗口协议窗口大小一般不同。发送方窗口内的序列号代表了那些已经被发送,但是还没有被确认的帧,或者是那些可以被发送的帧。
流量控制的处理过程:
- TCP连接阶段,双方协商窗口尺寸,同时接收方预留数据缓存区;
- 发送方根据协商的结果,发送符合窗口尺寸的数据字节流,并等待对方的确认;
- 发送方根据确认信息,改变窗口的尺寸,增加或者减少发送未得到确认的字节流中的字节数。调整过程包括:如果出现发送拥塞,发送窗口缩小为原来的一半,同时将超时重传的时间间隔扩大一倍。
可靠传输及丢包重试
1、UDP
UDP是尽最大努力保证数据不丢失,不提供可靠性传输,并且在丢包情况不支持重传的机制
2、TCP
对于可靠传输,判断丢包,误码靠的是TCP的段编号以及确认号。TCP为了保证报文传输的可靠,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的字节发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据(假设丢失了)将会被重传。
报文头结构
1、UDP
UDP 头部包含了以下几个数据:
- 两个十六位的端口号,分别为源端口(可选字段)和目标端口
- 整个数据报文的长度,占用两个字节
- 整个数据报文的检验和(IPv4 可选 字段),该字段用于发现头部信息和数据中的错误,占用两个字节
2、TCP
TCP头部包含如下几个数据
- 两个十六位的端口号,分别为源端口(可选字段)和目标端口
- 四个字节的序号
- 四个字节的确认序号
- 两个字节(首部字节+保留位和六个指令))
- 两个字节的窗口大小
- 两个字节的校验和
- 两个字节的紧急指针用于特殊情况的处理
- 以及选项内容,这块最多40字节
基于上述不同,UDP和TCP编程步骤也有些不同,如下:
TCP:
TCP编程的服务器端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt(); * 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();
4、开启监听,用函数listen();
5、接收客户端上来的连接,用函数accept();
6、收发数据,用函数send()和recv(),或者read()和write();
7、关闭网络连接;
8、关闭监听;
TCP编程的客户端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();* 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
4、设置要连接的对方的IP地址和端口等属性;
5、连接服务器,用函数connect();
6、收发数据,用函数send()和recv(),或者read()和write();
7、关闭网络连接;
UDP:
与之对应的UDP编程步骤要简单许多,分别如下:
UDP编程的服务器端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();* 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();
4、循环接收数据,用函数recvfrom();
5、关闭网络连接;
UDP编程的客户端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();* 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
4、设置对方的IP地址和端口等属性;
5、发送数据,用函数sendto(); 执行sendto时指定对方地址
6、关闭网络连接;