05_W5500_UDP通信

2023-12-13 04:08:02

上两节我们分别完成了的客户端和服务端的测试,这节我们要实现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

文章来源:https://blog.csdn.net/weixin_46364710/article/details/134826710
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。