8.1. SOCKETS

8.1.1. 概述

LWIP协议栈中SOCKET用法


8.1.2. DEMO工程

apps/demo/demo_DevkitBoard


8.1.3. TCP Client

示例说明

通过创建tcp socket连接到指定ip和端口号的服务端。当成功建立连接后,应用程序会向服务端发送ASCII数据, 并等待服务端回复,当客户端成功接收到服务端的数据后,会向服务端发送接收数据成功的信息。

TCP客户端创建步骤

1.创建socket

void *fd = NULL;
fd = sock_reg(AF_INET, SOCK_STREAM, 0, NULL, NULL);
if(NULL == fd)
{
        printf("sock_reg fail\n");
}

2.设置socket属性(可选)

//如:
unsigned int opt = 1;
if(sock_setsockopt(fd, IPPROTO_TCP, TCP_QUICKACK, &opt, sizeof(opt)) < 0)
{
        printf("sock_setsockopt fail\n");
}

3.绑定IP地址、端口号等信息(可选)

struct sockaddr_in local_addr;

local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = htonl(INADDR_ANY)
local_addr.sin_port = htons(32768);

if (sock_bind(fd, (struct sockaddr *)&local_addr), sizeof(local_addr))
{
        printf("sock_bind fail\n");
}

4.设置连接方IP和端口号, 并连接。

struct sockaddr_in dest_addr;

dest_addr.sin_family = AF_INET;
dest_addr.sin_addr.s_addr = inet_addr("192.168.1.1")
dest_addr.sin_port = htons(32769);

if(sock_connect(fd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in)))
{
        printf("sock_connect fail\n");
}

5.接收数据

char buf[1024] = {0};
int recv_len = sock_recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL);
if(recv_len > 0)
{
        printf("received %d Bytes, data : %s\n", recv_len, buf);
}

6.发送数据

char *send_buf = "123456";
int send_len = sock_send(fd, send_buf, strlen(send_buf), 0);

7.关闭socket

if(fd)
{
        sock_unreg(fd);
        fd = NULL;
}

示例

示例代码见 apps\common\example\network_protocols\sockets\tcp\client\main.c, 测试时需要在 apps/demo/demo_DevKitBoard/include/demo_config.h ,开启宏 USE_TCP_CLIENT_TEST

操作说明

  • 示例需要运行在STA模式 (注:如何进行sta和ap切换,请参考 Wi-Fi部分 )

  • 借助tcq助手创建指定ip和端口号的服务端,并保证tcp助手和客户端处于同一网段下

  • 编译工程,烧录镜像,复位启动

  • 系统启动并成功联网后,tcp助手会接收到客户端的ASCII数据,同时可以通过tcp助手向客户端发送数据,数据发送成功后可以通过串口软件看到服务端发送回来的数据

示例流程:

  • c_main() 入口
    1. 创建任务 tcp_client_start

  • tcp_client_start 函数流程
    1. 通过 wifi_get_sta_connect_state 函数检测是否通过dhcp成功获取到ip

    2. 成功通过dhcp获取到ip后,启动 tcp_client_task 任务,退出 tcp_client_start

  • tcp_client_task 任务流程
    1. 通过 tcp_client_init 进行TCP Client初始化,包括:创建socket,连接到服务端

    2. 通过 tcp_send_data 向服务端发送数据

    3. 通过 tcp_recv_data 接收服务端数据


8.1.4. TCP Server

示例说明

通过创建TCP socket并绑定指定端口后开启监听,等待客户端连接。当接收到客户端连接请求并成功建立连接后, 应用程序会等待接收客户端的数据,当服务端成功接收到客户端的数据后,会向对应客户端发送接收数据成功的信息。

TCP服务端创建步骤

1.创建socket

void *fd = NULL;
fd = sock_reg(AF_INET, SOCK_STREAM, 0, NULL, NULL);
if(NULL == fd)
{
        printf("sock_reg fail\n");
}

2.设置socket属性(可选)

 //如:
unsigned int opt = 1;
if(sock_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR ,&opt, sizeof(opt)) < 0)
{
       printf("sock_setsockopt fail\n");
}

3.绑定IP地址、端口号等信息(可选)

struct sockaddr_in local_addr;

local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = htonl(INADDR_ANY)
local_addr.sin_port = htons(32768);

if (sock_bind(fd, (struct sockaddr *)&local_addr), sizeof(local_addr))
{
        printf("sock_bind fail\n");
}

4.开启监听

if (sock_listen(fd, 3))
{
        printf("sock_listen fail\n");
}

5.等待客户端连接

void *c_fd = NULL;
int flag = 1;
struct sockaddr_in c_addr;
socklen_t len = sizeof(struct sockaddr_in);

c_fd = sock_accept(fd, (struct sockaddr*)&c_addr, &len, NULL, NULL);
flag = 0;
if(c_fd == NULL)
{
        printf("sock_accept fail\n");
}

6.接收数据

char buf[1024] = {0};
int recv_len = sock_recv(fd, buf, sizeof(buf), 0);
if(recv_len > 0)
{
        printf("received %d Bytes, data : %s\n", recv_len, buf);
}

7.发送数据

char *send_buf = "123456";
int send_len = sock_send(fd, send_buf, strlen(send_buf), 0);

8.关闭socket

if(fd)
{
        flag = 1;
        sock_set_quit(fd);
        while(flag)   //等待sock_accept退出后再释放socket,防止释放socket后还在使用。
        {
                os_time_dly(20);
        }
        sock_unreg(fd);
        fd = NULL;
}

示例

示例代码见 apps\common\example\network_protocols\sockets\tcp\server\main.c, 测试时需要在 apps/demo/demo_DevKitBoard/include/demo_config.h ,开启宏 USE_TCP_SERVER_TEST

操作说明

  • 系统启动并成功联网后,借助tcq助手创建客户端,设置好服务端ip和端口号后发起连接,成功连接后可以通过串口软件看到提示信息, 此时客户端可以向服务端发送一些数据,当服务端成功接收到数据后,会向对应客户端发送接收数据成功的信息。

示例流程如下:

  • c_main() 入口
    1. 创建 tcp_server_start 任务

  • tcp_server_start 函数流程
    1. 调用 tcp_server_init 进行初始化,退出 tcp_server_start

  • tcp_server_init 任务流程
    1. 创建TCP socket。

    2. 创建接收客户端连接请求任务 tcp_sock_accpet

    3. 创建接收客户端数据任务 tcp_recv_handler

  • tcp_sock_accpet 函数流程
    1. 等待客户端连接,成功接收到客户端请求后,会把对应客户端的信息保存到链表中

  • tcp_recv_handler 函数流程
    1. 接收客户端数据,成功接收到数据后,向对应客户端发送接收数据成功的信息

  • 调用 tcp_server_exit 可关闭网路连接,需要使用者自行调用


8.1.5. UDP Client

示例说明

UDP通信无需建立连接关系,创建套接字后便可以向指定服务端发送数据,示例请参考UDP Server

UDP客户端创建步骤

1.创建socket

void *fd = NULL;
fd = sock_reg(AF_INET, SOCK_DGRAM, 0, NULL, NULL);
if(NULL == fd)
{
        printf("sock_reg fail\n");
}

2.设置socket属性(可选)

//如:
unsigned int millsec = 100;
if(ock_setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (const void *)&millsec, sizeof(millsec)) < 0)
{
        printf("sock_setsockopt fail\n");
}

3.绑定IP地址、端口号等信息(可选)

struct sockaddr_in c_addr;

c_addr.sin_family = AF_INET;
c_addr.sin_addr.s_addr = htonl(INADDR_ANY)
c_addr.sin_port = htons(32768);

if (sock_bind(fd, (struct sockaddr *)&c_addr), sizeof(c_addr))
{
        printf("sock_bind fail\n");
}

4.接收数据

int recv_len;
char recv_buf[1024];
struct sockaddr_in s_addr = {0};
socklen_t len = sizeof(s_addr);

for(;;)
{
        recv_len = sock_recvfrom(fd, recv_buf, sizeof(recv_buf), 0, \
                                                        (struct sockaddr *)&s_addr, &len);
        if(recv_len > 0)
        {
                printf("received %d Bytes, data : %s\n", recv_len, recv_buf);
        }
}

5.发送数据

int send_len = sock_sendto(fd, send_buf, strlen(send_buf), 0, \
                                                   (struct sockaddr *)&s_addr, sizeof(struct sockaddr_in));

6.关闭socket

if(fd)
{
        sock_unreg(fd);
        fd = NULL;
}

8.1.6. UDP Server

示例说明

通过创建的udp socket并绑定指定ip和端口号后,等待接收客户端数据,当成功接收到数据后,再重新把接收到的数据发送回客户端。

UDP服务端创建步骤

1.创建socket

void *fd = NULL;
fd = sock_reg(AF_INET, SOCK_DGRAM, 0, NULL, NULL);
if(NULL == fd)
{
        printf("sock_reg fail\n");
}

2.设置socket属性(可选)

//如:
unsigned int opt = 1;
if(sock_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR ,&opt, sizeof(opt)) < 0)
{
        printf("sock_setsockopt fail\n");
}

3.绑定IP地址、端口号等信息

struct sockaddr_in s_addr;

s_addr.sin_family = AF_INET;
s_addr.sin_addr.s_addr = htonl(INADDR_ANY)
s_addr.sin_port = htons(32768);

if (sock_bind(fd, (struct sockaddr *)&s_addr), sizeof(s_addr))
{
        printf("sock_bind fail\n");
}

4.接收数据

int recv_len;
char recv_buf[1024];
struct sockaddr_in c_addr = {0};
socklen_t len = sizeof(c_addr);

for(;;)
{
        recv_len = sock_recvfrom(fd, recv_buf, sizeof(recv_buf), 0, \
                                                        (struct sockaddr *)&c_addr, &len);
        if(recv_len > 0)
        {
                printf("received %d Bytes, data : %s\n", recv_len, recv_buf);
        }
}

5.发送数据

int send_len = sock_sendto(fd, send_buf, strlen(send_buf), 0, \
                                                (struct sockaddr *)&c_addr, sizeof(struct sockaddr_in));

6.关闭socket

if(fd)
{
        sock_unreg(fd);
        fd = NULL;
}

操作说明

  • 示例需要运行在STA模式 (注:如何进行sta和ap切换,请参考 Wi-Fi部分 )

  • 编译工程,烧录镜像,复位启动。

  • 系统启动并成功联网后,借助tcp/udp助手向指定ip和端口号的UDP服务端发送数据,通过串口软件可以看到tcp/udp助手发送过来的数据,同时tcp/udp助手也会接收到客户端返回的同样的数据。

示例

示例代码见 apps\common\example\network_protocols\sockets\udp\server\main.c, 测试时需要在 apps/demo/demo_DevKitBoard/include/demo_config.h ,开启宏 USE_UDP_SERVER_TEST

示例流程如下:

  • c_main() 入口
    1. 创建 udp_server_start 任务

  • udp_server_start 函数流程
    1. 通过 wifi_get_sta_connect_state 函数检测是否通过dhcp成功获取到ip

    2. 成功通过dhcp获取到ip后,调用 udp_server_init 进行初始化,退出 udp_server_start

  • udp_server_init 函数流程

    A)创建UDP socket,绑定ip和端口号 B) 创建接收客户端数据任务 udp_recv_handler

  • udp_recv_handler 函数流程
    1. 等待接收客户端数据,成功接收到数据后再重新把同样的数据发回给客户端

  • 调用 udp_server_exit 可关闭连接