上两节我们分别完成了的客户端和服务端的测试,这节我们要实现W5500UDP通信。
目录
1.UDP通信介绍:
2.UDP的通信流程:
3.代码分析:
4.测试
1.UDP通信介绍:
UDP提供不可靠服务,具有TCP所没有的优势:
UDP无连接,时间上不存在建立连接需要的时延。空间上,TCP需要在端系统中维护连接状态,需要一定的开销。此连接装入包括接收和发送缓存,拥塞控制参数和序号与确认号的参数。UCP不维护连接状态,也不跟踪这些参数,开销小。空间和时间上都具有优势。
举个例子:
DNS如果运行在TCP之上而不是UDP,那么DNS的速度将会慢很多。HTTP使用TCP而不是UDP,是因为对于基于文本数据的Web网页来说,可靠性很重要。同一种专用应用服务器在支持UDP时,一定能支持更多的活动客户机。
分组首部开销小**,TCP首部20字节,UDP首部8字节。
UDP没有拥塞控制,应用层能够更好的控制要发送的数据和发送时间,网络中的拥塞控制也不会影响主机的发送速率。某些实时应用要求以稳定的速度发送,能容 忍一些数据的丢失,但是不能允许有较大的时延(比如实时视频,直播等)
UDP提供尽最大努力的交付,不保证可靠交付。所有维护传输可靠性的工作需要用户在应用层来完成。没有TCP的确认机制、重传机制。如果因为网络原因没有传送到对端,UDP也不会给应用层返回错误信息
UDP是面向报文的,对应用层交下来的报文,添加首部后直接乡下交付为IP层,既不合并,也不拆分,保留这些报文的边界。对IP层交上来UDP用户数据报,在去除首部后就原封不动地交付给上层应用进程,报文不可分割,是UDP数据报处理的最小单位。
正是因为这样,UDP显得不够灵活,不能控制读写数据的次数和数量。比如我们要发送100个字节的报文,我们调用一次sendto函数就会发送100字节,对端也需要用recvfrom函数一次性接收100字节,不能使用循环每次获取10个字节,获取十次这样的做法。
UDP常用一次性传输比较少量数据的网络应用,如DNS,SNMP等,因为对于这些应用,若是采用TCP,为连接的创建,维护和拆除带来不小的开销。UDP也常用于多媒体应用(如IP电话,实时视频会议,流媒体等)数据的可靠传输对他们而言并不重要,TCP的拥塞控制会使他们有较大的延迟,也是不可容忍的.
以上UDP介绍引用至UDP协议的详细解析-CSDN博客
2.UDP的通信流程:
客户端:打开socket,就可以调用sendto函数进行发送数据.
服务器:打开socket,进行绑定,就可以进行接收和发送数据.
3.代码分析:
在了解UDP通信后我们就可以对UDP代码进行分析和测试了.
大致流程:
1.进行单片机外设初始化spi、uart、at24c16等。
2.配置w5500网络信息。
3.进入socket状态机:
进入状态及后,socket处于关闭状态(SOCK_CLOSED),执行 socket(0, Sn_MR_UDP, local_port, 0);函数,成功打开socket后,状态就切换为SOCK_UDP,我们就可以调用recvfrom和sendto函数进行数据的收发测试了.
int main()
{
uint8 remote_ip[4] = {192, 168, 10, 2}; // 配置远程IP地址
uint16 remote_port = 6000; // 配置远程端口
uint16 local_port = 5000; // 初始化一个本地端口
uint16 len = 0;
/***** MCU时钟初始化 *****/
Systick_Init(72);
/***** GPIO、SPI初始化 *****/
GPIO_Configuration();
WIZ_SPI_Init();
/***** 串口初始化 *****/
USART1_Init();
/***** 初始化eeprom *****/
at24c16_init();
/***** 硬重启W5500 *****/
Reset_W5500();
/***** W5500的IP信息初始化 *****/
set_default(); // 设置默认MAC、IP、GW、SUB、DNS
set_network(); // 配置初始化IP信息并打印,初始化8个Socket
printf("UDP Local Port: %d \r\n", local_port);
printf("UDP Remote IP: %d.%d.%d.%d \r\n", remote_ip[0], remote_ip[1], remote_ip[2], remote_ip[3]);
printf("UDP Remote Port: %d \r\n", remote_port);
printf("W5500 Init Complete!\r\n");
printf("Start UDP Test!\r\n");
/*Socket状态机,MCU通过读Sn_SR(0)的值进行判断Socket应该处于何种状态
Sn_SR状态描述:
0x00 SOCK_CLOSED
0x13 SOCK_INIT
0x14 SOCK_LISTEN
0x17 SOCK_ESTABLISHED
0x1C SOCK_CLOSE_WAIT
0x22 SOCK_UDP
*/
while(1) // Socket状态机
{
switch(getSn_SR(0)) // 获取socket0的状态
{
case SOCK_UDP: // Socket处于初始化完成(打开)状态
Delay_ms(100);
if(getSn_IR(0) & Sn_IR_RECV)
{
setSn_IR(0, Sn_IR_RECV); // Sn_IR的RECV位置1
}
// 数据回环测试程序:数据从远程上位机发给W5500,W5500接收到数据后再回给远程上位机
if((len = getSn_RX_RSR(0)) > 0)
{
memset(buffer, 0, len + 1);
recvfrom(0, buffer, len, remote_ip, &remote_port); // W5500接收来自远程上位机的数据,并通过SPI发送给MCU
printf("%s\r\n", buffer); // 串口打印接收到的数据
sendto(0, buffer, len, remote_ip, remote_port); // 接收到数据后再回给远程上位机,完成数据回环
}
break;
case SOCK_CLOSED: // Socket处于关闭状态
socket(0, Sn_MR_UDP, local_port, 0); // 打开Socket0,并配置为UDP模式,打开一个本地端口
break;
}
}
}
4.测试:
与之前相同,我们仍要保持w5500配置的IP要和我们电脑的以太网IP地址在同一个网段内,我们使用电脑端的网络调试助手模拟UDP向我们的W5500发送数据 。
上图表示我们UDP的数据传输OK
04_W5500_TCP_Server<---------上一篇 下一篇----------> 06_W5500_DHCP