backgroundworker 设置为 sta_WIFI模块开发教程之W600网络篇3:STA模式下TCP Client通信...

前言

本文研究如何在STA模式下进行TCP Client通信,STA模式是说模块直接连接AP(手机热点或者路由器),进入局域网中和其他无线设备通信,局域网中其他设备作为服务端,WIFI模块作为客户端。

一、理论基础

本节主要要处理的有一个问题:如何利用RT_Thread连接一个已知的AP,连上AP后,TCP Client程序和网络篇1中内容完全一致。

1.模块连接AP

路由器名字:HUAWEI-6ZCHWJ,密码:123456789a:。

    rt_wlan_set_mode(RT_WLAN_DEVICE_AP_NAME, RT_WLAN_AP);       rt_wlan_start_ap("sand", "12345678");

2.Socket套接字实现TCP Client

为了编写一个可用的TCP Client demo,需要先了解套接字使用流程

a249963c8e6afc01a941f380f90df142.png

3.要点说明

由于本篇和网络篇1很相似,本以为如前言中所说的,直接把模块起softAP,换成连网的就OK了,几分钟的事情,实际代码写起来加上调试的时间大大超出了预期,下面我说下,写STA模式下的TCP Client demo遇到的具体问题。

首先是如文章开始所说的,把模块起来softAP的API换成连接路由器的API,这个核心功能实现起来还是轻松无压力,1-2分钟就搞定了,但是替换了API后,总感觉不是一个实际项目该有的操作,于是开始考虑,是不是需要等到模块连网成功后才创建TCP Client Thread,进行和局域网下服务器的通信,细想来,的确需要,于是开始搜索API,有没有检测到系统网络状态的函数,发现也是在wlan_mgnt.h有个时间管理的接口:rt_err_trt_wlan_register_event_handler(rt_wlan_event_t event, rt_wlan_event_handlerhandler, void *parameter);

995d94f274395393bb0319c677c84ca3.png

有了注册函数,接下里就好办了,在连接路由器之前,首先注册回调函数,有连网成功回调、连网失败回调、断开连接回调,如下:

ed2d9968fc6f1df43acb429818df2438.png

然后在连网成功回调中设置连网成功信号量,上图中在注册时间之后,调用连接到路由器的API函数,然后就是等待信号量,这样做的目的就是为了等系统连网成功后再进行之后的操作。

static void wifi_connect_callback(int event, struct rt_wlan_buff *buff, void *parameter){          rt_kprintf("%s", __FUNCTION__);          rt_sem_release(wait_sem);}

心里想着做到这一步,应该差不多了吧,于是乎,代码用scons编译后,跑一波,我天,模块跑着跑着突然断线了然后可恶的是它竟然断线后不重连了,于是接着找API,发现有个自动重连的函数没有设置,果断加上,如下:

rt_wlan_config_autoreconnect(RT_TRUE);

由此可见一个稳定的项目,往往是大量测试后优化的结晶。

二、使用实例

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 #include #include  //使用BSD socket需要包含此头文件#define TCP_SERVER_ADDR "192.168.1.13"#define TCP_SERVER_PORT 8089static rt_sem_t wait_sem = NULL;static void wifi_connect_callback(int event, struct rt_wlan_buff *buff, void *parameter){    rt_kprintf("%s", __FUNCTION__);    rt_sem_release(wait_sem);}static void wifi_disconnect_callback(int event, struct rt_wlan_buff *buff, void *parameter){    rt_kprintf("%s", __FUNCTION__);    if ((buff != RT_NULL) && (buff->len == sizeof(struct rt_wlan_info)))    {        rt_kprintf("ssid : %s", ((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", __FUNCTION__);    if ((buff != RT_NULL) && (buff->len == sizeof(struct rt_wlan_info)))    {        rt_kprintf("ssid : %s", ((struct rt_wlan_info *)buff->data)->ssid.val);    }}static void tcp_client_thread_entry(void *args){    int ret = 0;    int fd = -1;    struct sockaddr_in server_addr;    struct  timeval t;    fd_set readfds;    char buf[512] = { 0x00 };    int len = 0;reconnect:    fd = socket(AF_INET, SOCK_STREAM, 0);    if (-1 == fd)    {        rt_kprintf("create socket error!!!");        goto exit;    }    server_addr.sin_family = AF_INET;    server_addr.sin_port = htons(TCP_SERVER_PORT);    server_addr.sin_addr.s_addr = inet_addr( TCP_SERVER_ADDR );    rt_memset(&server_addr.sin_zero, 0x00, sizeof(server_addr.sin_zero));    ret = connect(fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr ));    if (0 == ret)    {        rt_kprintf("connect success");    }else    {        rt_kprintf("connect error!!!");        goto label_try_reconnect;    }        t.tv_sec = 2;    t.tv_usec = 0;    while (1)    {        FD_ZERO(&readfds);        FD_SET(fd, &readfds);        ret = select(fd + 1, &readfds, 0, 0, &t);        if (-1 == ret)        {            rt_kprintf("select() error!");            goto label_try_reconnect;        }        // else if(0 == ret)        // {        //     rt_kprintf("select() timeout!");        // }        else if(ret > 0)        {            if (FD_ISSET(fd, &readfds));            {                len = recv(fd, buf, sizeof(buf), 0);                if (len > 0)                {                    buf[len] = 0x00;                    rt_kprintf("receive data:%s", buf);                }else                {                    rt_kprintf("receive data from tcp server error!");                    goto label_try_reconnect;                }                if (-1 != fd)                {                    rt_sprintf(buf, "%s", buf);                    ret = send(fd, buf, strlen(buf), 0);                    if (ret < 0)                    {                        rt_kprintf("send error, closee socket");                        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 tcp_client exit!");}int main(void){    rt_err_t ret = RT_EOK;    char str[] = "hello world!";    // 创建一个动态信号量,初始值为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!");    }    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!");    }    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!");    }    // 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 ...");    // wait until module connect to ap success    ret = rt_sem_take(wait_sem, RT_WAITING_FOREVER);    if (0 != ret)    {        rt_kprintf("wait_sem error!");    }    rt_kprintf("connect to ap success!");    //create client    rt_thread_t client_thread = rt_thread_create("tcp_client", tcp_client_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目录下新建一个文件夹:5-sta_tcp_client,直接输入scons会提示编译错误,此时需要修改aplications/SConscript脚本。

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

三、下载运行

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

烧录运行后,电脑连接模块起来的热点,然后打开电脑网络调试助手,开启一个TCP Server,IP地址是电脑的IP地址,端口为8089,注意如果填错,网络助手是无法开启TCP Server的,设备连接到TCP Server后,通过网络助手发送hello world,模块收到数据后,会加上"",然后返回给网络助手。

网络助手界面如下:

de76b58e431f0d6f5d0941ccffb49ee1.png

模块调试串口信息如下:

8b23083c25ba846a3941d382d77f854a.png

四、结语

1.总结:

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

(1) 注意电脑连接模块后会得到一个IP地址,可以通过在cmd控制台中输入ipconfig

1dc84653bb369024980e0b6359ea8077.png

本文得到电脑IP为:192.168.1.13,因此电脑连接模块热点后,打开网络助手,需要设置TCP Server地址为192.168.1.13, Port端口可以自行定义,本文使用8089。

(2) 延时纠错

TCP Client重连的时候,rt_err_t rt_thread_sleep(rt_tick_t tick)的单位是tick不是秒,本代码已修改为rt_thread_mdelay(1000);

(3) 网络状态

本篇中没有针对网络状态做过多处理,实际项目使用中,需要根据注册的事件回调函数更新网络状态,一般断网的时候应该指示灯熄灭,连接成功的时候常亮,配网和连网过程中闪烁,关于配网在之后的文章中会有;再次提醒下,千万不要在int main(void)之后调用解除注册函数,释放连网前注册的函数,笔者之前不小心犯过这个错误,导致连网后网络状态变化,模块实际未同步给板卡,导致客户MCU控制的板卡还以为是正常在线的。解除注册接口如下:rt_err_t rt_wlan_unregister_event_handler(rt_wlan_event_tevent);对于其他资源需要酌情考虑是否需要删除,本篇中的连网等待信号量可以删除,回收系统资源:rt_sem_delete(wait_sem)。


作者:小驿

寄语:我不去想是否能够成功,既然选择了远方,便只顾风雨兼程!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值