物联网之WiFi三

WiFi网络编程上

1、网络协议栈LwIP

2、WiFi UDP Clinet编程

3、WiFi UDP Server编程

4、WiFi TCP Client编程

5、WiFi TCP Server编程

网络协议栈LwIP

1、LwIP介绍

2、LwIP应用API接口

LwIP介绍

LwIP介绍

LwIP(Light Weight Internet Protocol)是瑞典计算机科学院的Adam Dunkels等人开发的一套用于嵌入式系统的开源TCP/IP协议栈。

LwIP的含义是轻型IP协议,重点是在保持TCP协议主要功能的基础上减少对RAM的占用,这使得LwIP协议栈非常适合在小型嵌入式系统中使用。

LwIP支持的协议

网络分层

协议名称

协议描述

应用层

DNS client

域名解析协议

DHCP client

动态主机配置协议

SNMP

简单网络管理协议

传输层

UDP

用户数据报协议

TCP

一种面向连接的、可靠的、基于字节流的传输层通信协议

网络层

ICMP

Internet控制报文协议

IP(IPV4&IPV6)

网络之间互连的协议

网络接口和物理层

PPP

点对点协议

ARP

地址解析协议

LwIP应用接口

接口名称

接口描述

RAW API

 RAW API接口函数不仅在程序代码的执行时间上更快,而且在运行中它也占用更少的内存资源。唯一的缺点是应用程序的编写比较困难,并且代码较难理解。尽管如此,在CODERAM都较小的嵌入式系统中,优先考虑采用的方法。

BSD

Socket

API

BSD Socket API提供了基于open-read-write-close模型的UNIX标准API,它的最大特点是使应用程序移植到其它系统时比较容易,但用在嵌入式系统中效率比较低,占用资源多。

LwIP源码的文件结构

api目录:应用程序接口文件。

arch目录:与硬件和OS有关的文件,包括网络驱动、移植需要修改的文件。

core目录:LwIP的核心代码,包括ICMP、IP、UDP、TCP等协议的实现等。

include目录:LwIP的包含文件。

netif目录:PPP协议和LwIP网络设备驱动程序的模板,提供了网络接口驱动程序的基本框架。 

LwIP应用API接口

Socket 通信模型

Socket是一个网络编程接口

Socket类型:

    流式套接字(SOCK_STREAM)

    数据报套接字(SOCK_DGRAM)

    原始套接字(SOCK_RAW)

Socket API

socket:创建一个套接字

bind:将本地端口号和IP地址绑定到套接字上

listen:TCP监听

accept:TCP监听接受处理

connect:TCP客户端连接

select:特殊套接字设置

send/sendto:发送数据包到已连接/未连接套接字上

recv/recvfrom:接收数据包从已连接/未连接套接字上

getsockopt/setsockopt:获取/改变套接字选项

getpeername/getsockname:获取远端/本地地址信息

close:关闭套接字

shutdown:按设置关闭套接字

gethostbyname/gethostbyaddr:地址域名映射

read:从套接字缓存读数据

write:向套接字缓存写数据

LwIP Socket API

Lwip协议栈的实现目的,无非是要上层用来实现app的socket编程。

为了兼容性,lwip的socket通过宏定义提供标准的socket接口函数

socket

int socket (int domain, int type, int protocol);
domain 是地址族
PF_INET  // internet IPv4协议
PF_INET6 // internet IPv6协议
PF_UNSPEC      // 用户协议

type  // 套接字类型
SOCK_STREAM   // 流式套接字
SOCK_DGRAM    // 数据报套接字
SOCK_RAW         //  原始套接字

protocol //参数通常置为0
    IPPROTO_IP      0
    IPPROTO_TCP     6
    IPPROTO_UDP     17

bind

int bind (int sockfd, struct sockaddr* addr, int addrLen);
sockfd 由socket() 调用返回

addr 是指向 sockaddr_in 结构的指针,包含本机IP 地址和端口号
struct sockaddr_in
u_short sin_family // protocol family
u_short sin_port     // port number
struct in_addr  sin_addr  //IP address (32-bits)

addrLen : sizeof (struct sockaddr_in)

地址相关的数据结构

通用地址结构
  struct sockaddr
  {    
       u_short  sa_family;    // 地址族, AF_xxx
       char  sa_data[14];     // 14字节协议地址
  };

Internet协议地址结构
  struct sockaddr_in
  {           
       u_short sin_family;      // 地址族, AF_INET,2 bytes
       u_short sin_port;      // 端口,2 bytes
       struct in_addr sin_addr;  // IPV4地址,4 bytes 	
       char sin_zero[8];        // 8 bytes unused,作为填充
  }; 
IPv4地址结构
// internet address  
struct in_addr
{
     in_addr_t  s_addr;            // u32 network address 
};

地址结构的一般用法

定义一个struct sockaddr_in类型的变量并清空
struct sockaddr_in myaddr;
memset(&myaddr, 0, sizeof(myaddr));

填充地址信息
myaddr.sin_family = PF_INET;
myaddr.sin_port = htons(8888); 
myaddr.sin_addr.s_addr = inet_addr(“192.168.1.100”);

将该变量强制转换为struct sockaddr类型在函数中使用
bind(listenfd, (struct sockaddr*)(&myaddr), sizeof(myaddr));

地址转换函数

unsigned long inet_addr(char *address);
  address是以’\0’结尾的点分IPv4字符串。该函数返回32位的地址。如果字符串包含的不是合法的IP地址,则函数返回-1。例如:
struct in_addr addr;
addr.s_addr = inet_addr(" 192.168.1.100 ");

char* inet_ntoa(struct in_addr address);
  address是IPv4地址结构,函数返回一指向包含点分IP地址的静态存储区字符指针。如果错误则函数返回NULL

getsockopt/ setsockopt

int getsockopt(int sock, int level,int optname, void *optval, socklen_t *optlen);
int setsockopt(int sock, int level,int optname, const void *optval, socklen_t optlen);
参数:  
sock:将要被设置或者获取选项的套接字。
level:选项所在的协议层。
optname:需要访问的选项名。
optval:对于getsockopt(),指向返回选项值的缓冲。对于setsockopt(),指向包含新选项值的缓冲。
optlen:对于getsockopt(),作为入口参数时,选项值的最大长度。作为出口参数时,选项值的实际长度。对于setsockopt(),现选项的长度。
返回说明:  
成功执行时,返回0。失败返回-1,errno被设为以下的某个值  
EBADF:sock不是有效的文件描述词
EFAULT:optval指向的内存并非有效的进程空间
EINVAL:在调用setsockopt()时,optlen无效
ENOPROTOOPT:指定的协议层不能识别选项
ENOTSOCK:sock描述的不是套接字

listen

int listen (int sockfd, int backlog);

sockfd:监听连接的套接字

backlog

指定了正在等待连接的最大队列长度,它的作用在于处理可能同时出现的几个连接请求。

DoS(拒绝服务)攻击即利用了这个原理,非法的连接占用了全部的连接数,造成正常的连接请求被拒绝。

返回值: 0 或 -1

完成listen()调用后,socket变成了监听socket(listening socket).

accept

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) ;

返回值:已建立好连接的套接字或-1

sockfd : 监听套接字 

addr : 对方地址

addrlen:地址长度

listen()和accept()是TCP服务器端使用的函数

connect

int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);

返回值:0 或 -1

sockfd : socket返回的文件描述符

serv_addr : 服务器端的地址信息  

addrlen : serv_addr的长度 

connect()是客户端使用的调用。

send/sendto

ssize_t  send(int  socket,  const  void  *buffer,  size_t  length, int flags);

ssize_t  sendto(int s, const void *data, size_t size, int flags,

       const struct sockaddr *to, socklen_t tolen);

返回值:

成功:实际发送的字节数

失败:-1, 并设置errno

头文件:

#include <sys/socket.h>

buffer : 发送缓冲区首地址

length : 发送的字节数

flags : 发送方式(通常为0)

sendto()一般在UDP协议时使用

recv/recvfrom

ssize_t  recv(int  socket,  const  void  *buffer,  size_t  length, int flags);

ssize_t  recvfrom(int s, void *mem, size_t len, int flags,

              struct sockaddr *from, socklen_t *fromlen)

返回值:

成功:实际接收的字节数

失败:-1, 并设置errno

buffer : 发送缓冲区首地址

length : 发送的字节数

flags : 接收方式(通常为0)

recvfrom()一般在UDP协议时使用

套接字的关闭

int close(int sockfd);

关闭双向通讯

int shutdown(int sockfd, int howto);

TCP连接是双向的(是可读写的),当我们使用close时,会把读写通道都关闭,有时侯我们希望只关闭一个方向,这个时候我们可以使用shutdown。针对不同的howto,系统回采取不同的关闭方式。

howto = 0

关闭读通道,但是可以继续往套接字写数据。

howto = 1

和上面相反,关闭写通道。只能从套接字读取数据。 

howto = 2

关闭读写通道,和close()一样

WiFi UDP Clinet编程

1、功能分析

2、功能实现

功能分析

完成UDP Client功能开发

    PC模拟UDP Server,指定(IP,PORT),等待Client数据

    UDP Client向Sever发送“I am Client!”

    Sever收到数据后,向Client发送“I am Server!”

功能实现

新建udpclient工程目录

在SDK目录下新建udpclient目录:

拷贝Station目录下所有文件到udpclient目录下:

新建udpclient源码文件

在user目录下新建udpclient.c:

在include目录下新建udpclient.h:

Sourceinsight配置

代码实现

在udpclient.c下,添加

    udpclient初始化

    udpclient任务

在udpclient.h下声明

udpclient初始化

创建udpclient任务:

Udpclient任务流程

udpclient.h文件完整内容//注意文件头部和尾部都是参照SDK包中任意一个头文件来写的,这里不需要深究

#ifndef __UDPCLIENT_H__
#define __UDPCLIENT_H__

#ifdef __cplusplus
extern "C" {
#endif

void ATaskUdpClient( void *pvParameters );

void UdpClient_init(void);

#ifdef __cplusplus
}
#endif

#endif
udpclient.c文件完整内容

#include "esp_common.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "udpclient.h"

#define SERVERADDR "192.168.31.158"
#define SERVERPORT 8000

/******************************************************************************
 * FunctionName : ATaskUdpClient
 * Description  : ATaskUdpClient 任务实现
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ATaskUdpClient( void *pvParameters )
{
    int iVariableExample = 0;
    int fd = -1;

    int NetTimeOnt = 5000;//设置超时时间参数为5秒
    int ret;

    struct sockaddr_in ServerAddr;
    char udpmsg[48];//接收数据的缓存区

    STATION_STATUS StaStatus;//状态变量
    do
    {
        StaStatus = wifi_station_get_connect_status();//获取connect的状态
        vTaskDelay(100);//释放CPU占用(1秒钟),为了不占用太多资源,使其他任务也能执行
    }while(StaStatus != STATION_GOT_IP);//是否获取到ip地址,如果没有获取到就一直循环

    fd = socket(PF_INET,SOCK_DGRAM,0);//创建socket
    if(fd == -1)
    {
        printf("get socket fail!\n");
        vTaskDelete(NULL);
    }

    setsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,&NetTimeOnt,sizeof(int));//设置超时时间为5秒

    //赋值server信息
    memset(&ServerAddr,0,sizeof(ServerAddr));
    ServerAddr.sin_family = AF_INET;
    ServerAddr.sin_addr.s_addr = inet_addr(SERVERADDR);
    ServerAddr.sin_port = htons(SERVERPORT);
    ServerAddr.sin_len = sizeof(ServerAddr);

    for(;;)
    {
        sendto(fd,"I am UdpClient!",sizeof("I am UdpClient!"),\
               0,(struct sockaddr *)&ServerAddr,(socklen_t)ServerAddr.sin_len);

        do
         {
            ret = recvfrom(fd,udpmsg,48,\
               0,(struct sockaddr *)&ServerAddr,(socklen_t*)(&ServerAddr.sin_len));
            if(ret > 0)
            {
                printf("UdpServer:%s\n",udpmsg);
            }
            else
            {
                printf("UdpServer data is no!\n");
            }
         }while(ret == -1);
    }
    vTaskDelete( NULL );
}


/******************************************************************************
 * FunctionName : UdpClient_init
 * Description  : UdpClient_init 初始化 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void UdpClient_init(void)
{
    xTaskCreate(ATaskUdpClient, "UdpClient", 256, NULL, 4, NULL);//新建任务
}
user_main.c

#include "udpclient.h"
 
#define SSID "chuangkexueyuan"//wifi账号
#define PASSWORD "makeru2017"//wifi密码
/******************************************************************************
 * FunctionName : user_init
 * Description  : entry of user application, init user function here
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
user_init(void)
{
    printf("SDK version:%s\n", system_get_sdk_version());
    Led_init();
    wifi_set_opmode(STATION_MODE);//配置WiFi为Station模式
    struct station_config *config = (struct station_config *)\
        zalloc(sizeof(struct station_config));//动态的分配内存空间
    sprintf(config->ssid,SSID);
    sprintf(config->password,PASSWORD);
 
    wifi_station_set_config(config);//配置设置到寄存器里面
    free(config);//释放动态分配的内存
 
    wifi_station_set_auto_connect(TRUE);//启动wifi的一键连接
    
    /* need to set opmode before you set config */
   // wifi_set_opmode(STATION_MODE);
 
     UdpClient_init();//UdpClient_init 初始化:创建任务

    //xTaskCreate(smartconfig_task, "smartconfig_task", 256, NULL, 2, NULL);
    //xTaskCreate(ATaskLed, "LED", 256, NULL, 2, NULL);
}

 测试验证

UDP Client:

UDP Server:

WiFi UDP Server编程

1、功能分析

2、功能实现

功能分析

完成UDP Server功能开发

    PC模拟UDP Client,指定UDP Server (IP,PORT),发送“I am Client!”

    Sever收到数据后,向Client发送“I am Server!”

功能实现

新建udpserver工程目录

在SDK目录下新建udpserver目录:

拷贝udpclient目录下所有文件到udpserver目录下:

新建udpserver源码文件

在user目录下新建udpserver.c:

在include目录下新建udpserver.h:

Sourceinsight配置

代码实现

复制之前udpclient代码到udpserver上,进行修改

    重命名UdpClient_init为UdpServer_init

    重命名ATaskUdpClient为ATaskUdpServer

修改user_main.c

    包涵udpserver.h

    在user_init里修改为UdpServer_init

UdpServer任务流程

udpserver.h文件完整代码

#ifndef __UDPSERVER_H__
#define __UDPSERVER_H__

#ifdef __cplusplus
extern "C" {
#endif

void ATaskUdpServer( void *pvParameters );

void UdpServer_init(void);

#ifdef __cplusplus
}
#endif

#endif
udpserver.c文件完整代码

#include "esp_common.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "udpserver.h"

//#define SERVERADDR "192.168.31.158"
//#define SERVERPORT 8000

/******************************************************************************
 * FunctionName : ATaskUdpServer
 * Description  : ATaskUdpServer 任务实现函数
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ATaskUdpServer( void *pvParameters )
{
    int iVariableExample = 0;
    int fd = -1;

    int NetTimeOnt = 5000;
    int ret;

    struct sockaddr_in ServerAddr;
    struct sockaddr from;
    socklen_t fromlen = sizeof(struct sockaddr);
    char udpmsg[48];

    STATION_STATUS StaStatus;
    do
    {
        StaStatus = wifi_station_get_connect_status();
        vTaskDelay(100);
    }while(StaStatus != STATION_GOT_IP);

    fd = socket(PF_INET,SOCK_DGRAM,0);
    if(fd == -1)
    {
        printf("get socket fail!\n");
        vTaskDelete(NULL);
        return;
    }

    setsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,&NetTimeOnt,sizeof(int));//设置超时

    memset(&ServerAddr,0,sizeof(ServerAddr));
    ServerAddr.sin_family = AF_INET;
    ServerAddr.sin_addr.s_addr = INADDR_ANY;//获取当前的IP地址
    ServerAddr.sin_port = htons(SERVERPORT);
    ServerAddr.sin_len = sizeof(ServerAddr);

    if(bind(fd,(struct sockaddr*)&ServerAddr,ServerAddr.sin_len) != 0)//绑定
    {
        printf("bind socket fail!\n");
        vTaskDelete(NULL);
        return;
    }

    for(;;)
    {
        do
         {
            ret = recvfrom(fd,udpmsg,48,\
               0,&from,&fromlen);
            if(ret > 0)
            {
                printf("UdpClient:%s\n",udpmsg);
            }
            else
            {
                printf("UdpClient data is no!\n");
            }
         }while(ret == -1);

        sendto(fd,"I am UdpServer!",sizeof("I am UdpServer!"),\
               0,&from,fromlen);
    }
    vTaskDelete( NULL );
}

/******************************************************************************
 * FunctionName : UdpServer_init
 * Description  : UdpServer_init 初始化 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void UdpServer_init(void)
{
    xTaskCreate(ATaskUdpServer, "UdpServer", 256, NULL, 4, NULL);

}
user_main.c

#include "udpserver.h"
 
#define SSID "chuangkexueyuan"//wifi账号
#define PASSWORD "makeru2017"//wifi密码
/******************************************************************************
 * FunctionName : user_init
 * Description  : entry of user application, init user function here
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
user_init(void)
{
    printf("SDK version:%s\n", system_get_sdk_version());
    Led_init();
    wifi_set_opmode(STATION_MODE);//配置WiFi为Station模式
    struct station_config *config = (struct station_config *)\
        zalloc(sizeof(struct station_config));//动态的分配内存空间
    sprintf(config->ssid,SSID);
    sprintf(config->password,PASSWORD);
 
    wifi_station_set_config(config);//配置设置到寄存器里面
    free(config);//释放动态分配的内存
 
    wifi_station_set_auto_connect(TRUE);//启动wifi的一键连接
    
    /* need to set opmode before you set config */
   // wifi_set_opmode(STATION_MODE);
 
     UdpServer_init();//UdpClient_init 初始化:创建任务

    //xTaskCreate(smartconfig_task, "smartconfig_task", 256, NULL, 2, NULL);
    //xTaskCreate(ATaskLed, "LED", 256, NULL, 2, NULL);
}

 WiFi TCP Client编程

1、功能分析

2、功能实现

功能分析

完成TCP Client功能开发

    PC模拟TCP Server,指定(IP,PORT),等待Client数据

    TCP Client向Sever发送“I am Client!”

    Sever收到数据后,向Client发送“I am Server!”

功能实现

新建tcpclient工程目录

在SDK目录下新建tcpclient目录:

拷贝udpclient目录下所有文件到tcpclient目录下:

新建tcpclient源码文件

在user目录下新建tcpclient.c:

在include目录下新建tcpclient.h:

Sourceinsight配置

代码实现

复制之前udpclient代码到tcpclient上,进行修改

    重命名UdpClient_init为TcpClient_init

    重命名ATaskUdpClient为ATaskTcpClient

修改user_main.c

    包涵tcpclient.h

    在user_init里修改为TcpClient_init

tcpclient任务流程

udpclient.h文件完整代码

#ifndef __TCPCLIENT_H__
#define __TCPCLIENT_H__

#ifdef __cplusplus
extern "C" {
#endif

void ATaskTcpClient( void *pvParameters );

void TcpClient_init(void);

#ifdef __cplusplus
}
#endif

#endif
#include "esp_common.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "tcpclient.h"

#define SERVERADDR "192.168.31.158"
#define SERVERPORT 8000

/******************************************************************************
 * FunctionName : ATaskTcpClient
 * Description  : ATaskTcpClient 实现函数
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ATaskTcpClient( void *pvParameters )
{
    int iVariableExample = 0;
    int fd = -1;

    int NetTimeOnt = 5000;
    int ret;

    struct sockaddr_in ServerAddr;
    char Tcpmsg[48];

    STATION_STATUS StaStatus;
    do
    {
        StaStatus = wifi_station_get_connect_status();
        vTaskDelay(100);
    }while(StaStatus != STATION_GOT_IP);

    fd = socket(PF_INET,SOCK_STREAM,0);
    if(fd == -1)
    {
        printf("get socket fail!\n");
        vTaskDelete(NULL);
    }

    setsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,&NetTimeOnt,sizeof(int));

    memset(&ServerAddr,0,sizeof(ServerAddr));
    ServerAddr.sin_family = AF_INET;
    ServerAddr.sin_addr.s_addr = inet_addr(SERVERADDR);
    ServerAddr.sin_port = htons(SERVERPORT);
    ServerAddr.sin_len = sizeof(ServerAddr);

    do
        {
            ret = connect(fd,(struct sockaddr*)&ServerAddr,ServerAddr.sin_len);
            if(ret != 0)
            {
                printf("connect is fail!\n");
                vTaskDelay(100);
            }
        }
    while (ret != 0);
    
    for(;;)
    {
        send(fd,"I am TcpClient!",sizeof("I am TcpClient!"),0);

        do
         {
            ret = recv(fd,Tcpmsg,48,0);
            if(ret > 0)
            {
                printf("TcpServer:%s\n",Tcpmsg);
            }
            else
            {
                printf("TcpServer data is no!\n");
            }
         }while(ret == -1);
    }
    vTaskDelete( NULL );
}

/******************************************************************************
 * FunctionName : TcpClient_init
 * Description  : TcpClient_init 初始化
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void TcpClient_init(void)
{
    xTaskCreate(ATaskTcpClient, "TcpClient", 256, NULL, 4, NULL);
}
user_main.c

#include "tcpclient.h"
 
#define SSID "chuangkexueyuan"//wifi账号
#define PASSWORD "makeru2017"//wifi密码
/******************************************************************************
 * FunctionName : user_init
 * Description  : entry of user application, init user function here
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
user_init(void)
{
    printf("SDK version:%s\n", system_get_sdk_version());
    Led_init();
    wifi_set_opmode(STATION_MODE);//配置WiFi为Station模式
    struct station_config *config = (struct station_config *)\
        zalloc(sizeof(struct station_config));//动态的分配内存空间
    sprintf(config->ssid,SSID);
    sprintf(config->password,PASSWORD);
 
    wifi_station_set_config(config);//配置设置到寄存器里面
    free(config);//释放动态分配的内存
 
    wifi_station_set_auto_connect(TRUE);//启动wifi的一键连接
    
    /* need to set opmode before you set config */
   // wifi_set_opmode(STATION_MODE);
 
     TcpClient_init();//UdpClient_init 初始化:创建任务

    //xTaskCreate(smartconfig_task, "smartconfig_task", 256, NULL, 2, NULL);
    //xTaskCreate(ATaskLed, "LED", 256, NULL, 2, NULL);
}

WiFi TCP Server编程

1、功能分析

2、功能实现

功能分析

完成TCP Server功能开发

    PC模拟TCP Client,指定Server(IP,PORT)进行连接,连接成功后发生“I am Client!”

    Sever收到数据后,向Client发送“I am Server!”

功能实现

新建tcpserver工程目录

在SDK目录下新建tcpserver目录:

拷贝tcpclient目录下所有文件到tcpserver目录下:

新建tcpserver源码文件

在user目录下新建tcpserver.c:

在include目录下新建tcpserver.h:

Sourceinsight配置: 

代码实现

复制之前tcpclient代码到tcpserver上,进行修改

    重命名TcpClient_init为TcpServer_init

    重命名ATaskTcpClient为ATaskTcpServer

修改user_main.c

    包涵tcpserver.h

    在user_init里修改为TcpServer_init

tcpserver任务流程

tcpserver.h文件完整代码

#ifndef __TCPSERVER_H__
#define __TCPSERVER_H__

#ifdef __cplusplus
extern "C" {
#endif

void ATaskTcpServer( void *pvParameters );

void TcpServer_init(void);

#ifdef __cplusplus
}
#endif

#endif
tcpserver.c文件完整代码

#include "esp_common.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "tcpserver.h"

#define SERVERADDR "192.168.31.158"
#define SERVERPORT 8000

/******************************************************************************
 * FunctionName : ATaskTcpServer
 * Description  : ATaskTcpServer 实现函数
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ATaskTcpServer( void *pvParameters )
{
    int iVariableExample = 0;
    int fd = -1;
    int cfd = -1;
    int NetTimeOnt = 20000;
    int ret;

    struct sockaddr_in ServerAddr;
    struct sockaddr ClientAddr;
    socklen_t ClientAddrlen = sizeof(struct sockaddr);
    char Tcpmsg[48];

    STATION_STATUS StaStatus;
    do
    {
        StaStatus = wifi_station_get_connect_status();
        vTaskDelay(100);
    }while(StaStatus != STATION_GOT_IP);

    fd = socket(PF_INET,SOCK_STREAM,0);
    if(fd == -1)
    {
        printf("get socket fail!\n");
        vTaskDelete(NULL);
        return;
    }

    setsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,&NetTimeOnt,sizeof(int));

    memset(&ServerAddr,0,sizeof(ServerAddr));
    ServerAddr.sin_family = AF_INET;
    ServerAddr.sin_addr.s_addr = INADDR_ANY;
    ServerAddr.sin_port = htons(SERVERPORT);
    ServerAddr.sin_len = sizeof(ServerAddr);

    if(bind(fd,(struct sockaddr*)&ServerAddr,ServerAddr.sin_len) != 0)
    {
        printf("bind socket fail!\n");
        vTaskDelete(NULL);
        return;
    }

    if(listen(fd,5) != 0)
    {
        printf("listen socket fail!\n");
        vTaskDelete(NULL);
        return;
    }
   
    for(;;)
    {
        cfd = accept(fd,&ClientAddr,&ClientAddrlen);
        if(cfd != -1)
        {
            ret = recv(cfd,Tcpmsg,48,0);
            if(ret > 0)
            {
                printf("TcpClient:%s\n",Tcpmsg);
                send(cfd,"I am TcpServer!",sizeof("I am TcpServer!"),0);
            }
            else
            {
                printf("TcpClient data is no!\n");
            }
        }
        close(cfd);
    }
    vTaskDelete( NULL );
}

/******************************************************************************
 * FunctionName : TcpServer_init
 * Description  : TcpServer_init 初始化 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void TcpServer_init(void)
{

    xTaskCreate(ATaskTcpServer, "TcpServer", 256, NULL, 4, NULL);

}
user_main.c

#include "tcpserver.h"
 
#define SSID "chuangkexueyuan"//wifi账号
#define PASSWORD "makeru2017"//wifi密码
/******************************************************************************
 * FunctionName : user_init
 * Description  : entry of user application, init user function here
 * Parameters   : none
 * Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR
user_init(void)
{
    printf("SDK version:%s\n", system_get_sdk_version());
    Led_init();
    wifi_set_opmode(STATION_MODE);//配置WiFi为Station模式
    struct station_config *config = (struct station_config *)\
        zalloc(sizeof(struct station_config));//动态的分配内存空间
    sprintf(config->ssid,SSID);
    sprintf(config->password,PASSWORD);
 
    wifi_station_set_config(config);//配置设置到寄存器里面
    free(config);//释放动态分配的内存
 
    wifi_station_set_auto_connect(TRUE);//启动wifi的一键连接
    
    /* need to set opmode before you set config */
   // wifi_set_opmode(STATION_MODE);
 
     TcpServer_init();//UdpClient_init 初始化:创建任务

    //xTaskCreate(smartconfig_task, "smartconfig_task", 256, NULL, 2, NULL);
    //xTaskCreate(ATaskLed, "LED", 256, NULL, 2, NULL);
}

猜你喜欢

转载自blog.csdn.net/weixin_39148042/article/details/82057315