快捷搜索:  汽车  科技

路由器tcp和udp设置(WIFI模块开发教程之W600网络篇4)

路由器tcp和udp设置(WIFI模块开发教程之W600网络篇4)(3)TCP对系统资源要求较高,UDP较小(2)UDP程序结构较简单UDP工作原理可以用信件来说明,寄信之前需要在信封上写上寄信人和收信人的地址,之后贴上邮票放进信箱即可,使用信件方式,我们无法确认对方是否收到,寄信过程中也可能发生丢失信件情况,总而言之,信件是一种不可靠的传输方式,UDP也是类似,提供不可靠的通信服务。UDP和TCP的区别?(1)TCP是基于连接的服务,UDP是基于无连接的服务

前言

本文研究如何使用UDP进行数据通信,模块连上路由后,绑定2000端口,监听数据,收到数据后,原路发送回去。

一、 理论基础

1.理解UDP

UDP工作原理可以用信件来说明,寄信之前需要在信封上写上寄信人和收信人的地址,之后贴上邮票放进信箱即可,使用信件方式,我们无法确认对方是否收到,寄信过程中也可能发生丢失信件情况,总而言之,信件是一种不可靠的传输方式,UDP也是类似,提供不可靠的通信服务。

UDP和TCP的区别?

(1)TCP是基于连接的服务,UDP是基于无连接的服务

(2)UDP程序结构较简单

(3)TCP对系统资源要求较高,UDP较小

(4)TCP是基于流模式,UDP基于数据包模式,是两者间最大区别

(5)TCP保证数据正确性,UDP可能丢包

(6)TCP保证数据顺序,UDP不保证

2.要点说明

模块上电首先连接路由器,连接相关的操作和前文完全一致,需要做的就是在连接路由器之后处理UDP通信,UDP通信代码中常用的也是最核心的是sendto和recvfrom两个函数。

int sendto(ints const void *dataptr size_tsize intflags const structsockaddr*to socklen_ttolen)

  • 参数
  • s套接字描述符
  • dataptr发送的数据指针
  • size发送的数据长度
  • flags标志,一般为0
  • to目标地址结构体指针
  • tolen目标地址结构体长度
  • 返回
  • 大于0 成功,返回发送的数据的长度;小于等于0 失败。

int recvfrom(ints void *mem size_tlen intflags structsockaddr*from socklen_t *fromlen)

  • 参数
  • s套接字描述符mem接收的数据指针len接收的数据长度
  • flags标志,一般为0
  • from接收地址结构体指针
  • fromlen接收地址结构体长度
  • 返回
  • 大于0 成功,返回接收的数据的长度;等于0 接收地址已传输完并关闭连接;小于0 失败。

除了这两个函数还有一个bind函数也很重要,这里将重点说下bind函数 UDP程序中调用sendto函数传输数据前应完成对套接字的地址分配工作,而bind函数的作用就在此,bind在TCP程序中也出现过,但是bind函数不区分TCP和UDP,都可以使用。另外如果调用sendto函数时候发现尚未分配地址信息,则在首次调用sendto函数时候给响应套接字自动分配IP和端口,因此,UDP客户端程序中通常无需额外的地址分配过程。

二、使用实例

1.程序

/* * Copyright (c) 2019 Winner Microelectronics Co. Ltd. * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2019-02-13 tyx first implementation */ #include <rtthread.h> #include <rtdevice.h> #include <sys/socket.h> //使用BSD socket需要包含此头文件 #define UDP_LOCAL_PORT 2000 static rt_sem_t wait_sem = NULL; char *send_data = "hello UDP object!\r\n"; static void wifi_connect_callback(int event struct rt_wlan_buff *buff void *parameter) { rt_kprintf("%s\n" __FUNCTION__); rt_sem_release(wait_sem); } static void wifi_disconnect_callback(int event struct rt_wlan_buff *buff void *parameter) { rt_kprintf("%s\n" __FUNCTION__); if ((buff != RT_NULL) && (buff->len == sizeof(struct rt_wlan_info))) { rt_kprintf("ssid : %s\r\n" ((struct rt_wlan_info *)buff->data)->ssid.val); } } static void wifi_connect_fail_callback(int event struct rt_wlan_buff *buff void *parameter) { rt_kprintf("%s\n" __FUNCTION__); if ((buff != RT_NULL) && (buff->len == sizeof(struct rt_wlan_info))) { rt_kprintf("ssid : %s\r\n" ((struct rt_wlan_info *)buff->data)->ssid.val); } } static void udp_thread_entry(void *args) { int ret = 0; int fd = -1; struct sockaddr_in addr remote_addr; socklen_t addrLen = sizeof(addr); struct timeval t; fd_set readfds; char buf[512] = { 0x00 }; int len = 0; reconnect: fd = socket(AF_INET SOCK_DGRAM 0); if (-1 == fd) { rt_kprintf("create socket error!!!\r\n"); goto exit; } addr.sin_family = AF_INET; addr.sin_port = htons(UDP_LOCAL_PORT); addr.sin_addr.s_addr = INADDR_ANY; rt_memset(&addr.sin_zero 0x00 sizeof(addr.sin_zero)); ret = bind( fd (struct sockaddr *)&addr sizeof(addr)); if (0 != ret) { rt_kprintf("bind addr error!!!\r\n"); } while (1) { len = recvfrom(fd buf sizeof(buf) 0 (struct sockaddr *)&addr &addrLen); if (len > 0) { buf[len] = 0x00; rt_kprintf("receive data:%s from %s:%d\r\n" buf inet_ntoa(addr.sin_addr) addr.sin_port); sendto(fd buf len 0 (struct sockaddr *)&addr sizeof(struct sockaddr_in) ); }else { rt_kprintf("receive data from tcp server error!\r\n"); goto label_try_reconnect; } } label_try_reconnect: if (-1 != fd) { closesocket(fd); } rt_thread_mdelay(1000); goto reconnect; exit: if (-1 != fd) { closesocket(fd); } rt_kprintf("thread udp exit!\r\n"); } int main(void) { rt_err_t ret = RT_EOK; char str[] = "hello world!\r\n"; // 创建一个动态信号量,初始值为0 wait_sem = rt_sem_create("sem_conn" 0 RT_IPC_FLAG_FIFO); /* Start automatic connection */ rt_wlan_config_autoreconnect(RT_TRUE); // register event ret = rt_wlan_register_event_handler(RT_WLAN_EVT_STA_CONNECTED wifi_connect_callback RT_NULL); if (0 != ret) { rt_kprintf("register event handler error!\r\n"); } ret = rt_wlan_register_event_handler(RT_WLAN_EVT_STA_DISCONNECTED wifi_disconnect_callback RT_NULL); if (0 != ret) { rt_kprintf("register event handler error!\r\n"); } ret = rt_wlan_register_event_handler(RT_WLAN_EVT_STA_CONNECTED_FAIL wifi_connect_fail_callback RT_NULL); if (0 != ret) { rt_kprintf("register event handler error!\r\n"); } // connect to router rt_wlan_set_mode(RT_WLAN_DEVICE_STA_NAME RT_WLAN_STATION); rt_wlan_connect("HUAWEI-6ZCHWJ" "123456789a"); rt_kprintf("start to connect ap ...\n"); // wait until module connect to ap success ret = rt_sem_take(wait_sem RT_WAITING_FOREVER); if (0 != ret) { rt_kprintf("wait_sem error!\r\n"); } rt_kprintf("connect to AP success!\r\n"); //create udp thread rt_thread_t client_thread = rt_thread_create("udp" udp_thread_entry RT_NULL 4*1024 25 10); if (client_thread != NULL) { rt_thread_startup(client_thread); }else { ret = RT_ERROR; rt_kprintf("create tcp client error!!!"); } exit: rt_sem_delete(wait_sem); return ret; }

2.配置

在applications目录下新建一个文件夹:6-udp_unicast,然后同理需要修改aplications/SConscript脚本。

Import('RTT_ROOT') Import('rtconfig') from building import * cwd = GetCurrentDir() src = Glob('6-udp_unicast/main.c') CPPPATH = [cwd] group = DefineGroup('Applications' src depend = [''] CPPPATH = CPPPATH) Return('group')

三、下载运行

在ENV控制台,输入scons命令,在build/Bin目录下生成rtthread_1M.FLS,

烧录运行后,电脑连接模块起来的热点,然后打开电脑网络调试助手,开启一个UDP服务,IP地址是电脑的IP地址,端口为8089(可自行定义),模块启动UDP服务之后,通过网络助手发送hello world 模块收到数据后,返回给网络助手。

网络助手界面如下:

路由器tcp和udp设置(WIFI模块开发教程之W600网络篇4)(1)

块调试串口信息如下:

路由器tcp和udp设置(WIFI模块开发教程之W600网络篇4)(2)

四、结语

1.总结:

本节完,实际操作过程中需要注意的地方有如下几点:

(1) 解决hardfault问题

路由器tcp和udp设置(WIFI模块开发教程之W600网络篇4)(3)

程序运行过程中,偶先hardfault问题,从提示的任务状态信息可以看到tcpip thread使用了100% 发生溢出,由此可知,需要增大tcpip线程堆栈大小。

修改地方在bsp/w60x/rt_config.h文件中 具体位置如下图所示:

路由器tcp和udp设置(WIFI模块开发教程之W600网络篇4)(4)

将1024增大为4096即可。

​本文由小驿原创,欢迎关注,带你一起长知识!

寄语:人的成熟是从认识到自己的不完美开始!

猜您喜欢: