中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

LiteOS的SAL及socket編程方法是什么

發布時間:2021-12-29 10:24:36 來源:億速云 閱讀:156 作者:iii 欄目:互聯網科技

這篇文章主要講解了“LiteOS的SAL及socket編程方法是什么”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“LiteOS的SAL及socket編程方法是什么”吧!

1. SAL套接字抽象層

SAL全稱Socket Abstract Layer,即套接字抽象層,主要作用是對上層應用提供一層統一的 socket 編程接口,屏蔽底層網絡硬件的差異。

LiteOS的SAL架構如下:

LiteOS的SAL及socket編程方法是什么

SAL的優勢從圖中一看即知:

無論底層使用以太網+LwIP協議棧組合,還是使用ESP8266/M26+AT框架組合,經過SAL套接字抽象層之后,對用戶提供的接口都是統一的,極大的提高了程序的可移植性。

SAL框架的源碼及其實現在SDK中的IoT_LINK_1.0.0\iot_link\network\tcpip目錄:

LiteOS的SAL及socket編程方法是什么

除了sal文件夾之外,其余的文件夾分別對應著不同的sal實現,比如esp8266_socket對應的是基于AT框架和ESP8266的SAL實現。

SAL相關的頭文件存放在IoT_LINK_1.0.0\iot_link\inc文件夾中,如圖:

LiteOS的SAL及socket編程方法是什么

  • sal.h:SAL頭文件,使用時需包含;

  • sal_imp.h:抽象接口定義頭文件;

  • sal_types.h:socket編程中涉及到的類型定義;

  • sal_define.h:socket編程中涉及到的宏定義;

  • link_endian.h:socket編程中的大小端字節序轉換函數定義;

2. Socket編程基礎

2.1. Socket概述

Socket稱為套接字,本質上是一種文件描述符,所以socket通信的過程和操作文件的方法基本類似。

TCP/IP協議族的傳輸層中,分為有連接的,可靠的TCP傳輸方式,和無連接的,不可靠的UDP傳輸方式,所以Socket分為兩種:

  • 流式Socket(SOCK_STREAM):提供可靠的、面向連接的通信流,使用TCP協議;

  • 數據報Socket(SOCK_DGRAM):提供一種無連接的服務,使用UDP協議;

2.2. Socket結構體

一個標準的Socket應該包括以下五部分:

  • 協議類型

  • 目的IP

  • 目的端口

  • 源ip

  • 源端口

SAL提供了兩種socket的結構體用于存放數據,sockaddr結構體和sockaddr_in結構體,定義均在sal_types.h文件中。

sockaddr結構體的定義如下:

struct sockaddr
{
    sa_family_t     sa_family;      /* address family, AF_xxx   */
    char            sa_data[14];    /* 14 bytes of protocol address */
};

參數說明如下:

  • sa_family:地址族,一般為AF_INET,表示IPv4協議;

  • sa_data:包含了源ip、源端口、目的ip、目的端口;

sockaddr_in結構體的定義如下:

struct sockaddr_in
{
    sa_family_t sin_family;             /* AF_INET */
    in_port_t sin_port;                 /* Port number.  */
    struct in_addr sin_addr;            /* Internet address.  */
    unsigned char sin_zero[8];          /* Pad to size of `struct sockaddr'.  */
};

sockaddr結構體將所有的ip和端口信息都放在了sa_data中,不利用編程,而sockaddr_in結構體本質上和sockaddr結構體一樣,但是將目的ip和目的端口分離出來,容易編程,所以一般在使用的時候有如下技巧:

使用sockaddr_in結構體賦值,作為參數傳遞時強制轉換為sockaddr類型傳遞

2.3. 字節序轉換函數

在sockaddr_in結構體中填寫sin_port和sin_addr這兩個值時,需要注意:

  • in_port_tuint16_t類型;

  • sin_addruint32_t類型;

這樣就涉及到了兩個轉換問題:

  • ip地址的轉換

ip地址通常是一個字符串,比如"192.168.1.100",但是此處需要轉換為一個uint32_t類型的數據,SAL提供了一個轉換函數,在之前提到的link_endian.h文件中,函數如下:


  • 字節序的轉換

字節序分為大端存儲和小端存儲,為了保證統一性,屏蔽硬件差異,需要將ip地址和端口的值轉換為網絡字節序,SAL提供了本地字節序和網絡字節序的互相轉換函數,在link_endian.h文件中,其中h表示host主機,n表示network網絡字節序

htonl(unsigned long int hostlong);
htons(unisgned short int hostshort);
ntohl(unsigned long int netlong);
ntohs(unsigned short int netshort);

3. AT框架和SAL配置及開啟

本實驗中我們使用ESP8266+AT框架+SAL進行實驗,所以需要開啟使能AT框架和SAL。

3.1. AT框架開啟

關于AT框架具體的剖析,可以閱讀上一篇教程。

在工程目錄下的.sdkconfig中手動配置開啟驅動框架(串口使用)和AT框架:

LiteOS的SAL及socket編程方法是什么

實驗中使用的是ESP8266,所以還需要配置路由器的SSID和PASSWD,在SDK目錄中IoT_LINK_1.0.0\iot_link\network\tcpip\esp8266_socket目錄下, 打開esp8266_socket_imp.h文件:

在其中設置ESP8266連接的熱點名稱和密碼,這里我的設置如下:

LiteOS的SAL及socket編程方法是什么

最后,需要修改同文件夾下的esp8266_socket_imp.mk文件,將圖中標出的兩處TOP_DIR改為SDK_DIR:

LiteOS的SAL及socket編程方法是什么

LiteOS的SAL及socket編程方法是什么

3.2. SAL開啟

SAL默認是未開啟的,需要在工程目錄下的.sdkconfig中手動配置開啟:

LiteOS的SAL及socket編程方法是什么

其中CONFIG_TCPIP_ENABLE = y需要自己添加,CONFIG_TCPIP_TYPE宏定義的值目前支持,可以根據自己的需求選擇:

  • "lwip_socket"

  • "linux_socket"

  • "macos_socket"

  • "esp8266_socket"

  • "none"

注意:兩個宏定義必須同時存在且使能,SAL才會生效。

3.3. SAL自動初始化

使能了SAL之后,系統會自動進行初始化,在SDK目錄中的IoT_LINK_1.0.0\iot_link下的link_main.c文件中即可看到:

LiteOS的SAL及socket編程方法是什么

4. TCP Socket客戶端編程實例

4.1. TCP服務端的建立

在本實驗中,TCP Server使用網絡調試助手模擬,在本機8000端口開啟一個TCP服務器,如圖:

LiteOS的SAL及socket編程方法是什么

4.2. SAL提供的Socket客戶端編程API

建立socket

API原型如下:

int sal_socket(int domain, int type, int protocol);

參數說明如下:

參數說明常用值
domain協議或地址族AF_INET,表示IPv4
typesocket類型SOCK_STREAM,表示TCP


SOCK_DGRAM,表示UDP
protocol使用的協議號0,表示使用默認協議號
返回值socket描述符int類型值,-1則表示失敗

連接服務器socket

API原型如下:

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

參數說明如下:

參數說明
sockfd創建成功的sockfd描述符
addrsockaddr結構體指針
addrlensockaddr結構體長度

socket發送數據

API原型如下:

int sal_send(int sockfd,const void *buf,size_t len,int flags);

參數說明如下:

參數說明
sockfd創建成功的sockfd描述符
buf發送數據
len發送數據長度
flags發送或接收標記,一般都設為0

socket接收數據(非堵塞)

API原型如下:

int sal_recv(int sockfd,void *buf,size_t len,int flags);

參數說明如下:

參數說明
sockfd創建成功的sockfd描述符
buf接收數據緩沖區
len接收數據緩沖區長度
flags發送或接收標記,一般都設為0

關閉socket

API原型如下:

int sal_closesocket(int sockfd);

參數說明如下:

參數說明
sockfd創建成功的sockfd描述符

4.3. 基于SAL的TCP客戶端編程

打開之前創建的HelloWorld工程(如果沒有,可以參考第一篇教程新建),創建下面的文件夾sal_test_demo,并在該文件夾中新建一個測試文件sal_tcp_demo.c

LiteOS的SAL及socket編程方法是什么

編輯以下內容:

注意,其中的server_ip和server_port應該是服務器的實際情況相對應!

#include <osal.h>
#include <sal.h>

#define server_port 8000
#define server_ip   "192.168.0.101"

static int sal_tcp_demo_entry()
{
    int sockfd;

    /* 創建TCP socket */
    sockfd = sal_socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd < 0)
    {
        printf("TCP Socket create fail.\r\n");
        return -1;
    }
    else
    {
        printf("TCP Socket create ok.\r\n");
    }

    /* 連接服務器 */
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(server_port);
    server_addr.sin_addr.s_addr = inet_addr(server_ip);
    while(-1 == sal_connect(sockfd, (struct sockaddr*)&server_addr, sizeof(struct sockaddr)))
    {
        //連接失敗,則1s后自動重連
        printf("connect server fail, repeat...\r\n");
        osal_task_sleep(1000);
    }
    printf("connect server ok.\r\n");
    
    int nbytes;
    char buf[] = "hello server!";
    //發送數據到服務器
    nbytes = sal_send(sockfd, buf, sizeof(buf), 0);
    if(nbytes < 0)
    {
        printf("send dat %s fail.\r\n", buf);
        return -1;
    }
    else
    {
        printf("send [%d] bytes: %s.\r\n", nbytes , buf);
    }

    //等待接收服務器數據
    char recv_buf[50]={0};
    while( -1 == (nbytes = sal_recv(sockfd, recv_buf, 50, 0)));
    printf("recv [%d] bytes: %s.\r\n", nbytes, recv_buf);

    //關閉socket
    sal_closesocket(sockfd);
    printf("TCP socket closed.\r\n");

    return 0;
}

int standard_app_demo_main()
{
    osal_task_create("sal_tcp_demo",sal_tcp_demo_entry,NULL,0x800,NULL,12);
    return 0;
}

然后在user_demo.mk中添加文件路徑:

	#example for sal_tcp_demo
	ifeq ($(CONFIG_USER_DEMO), "sal_tcp_demo")	
		user_demo_src  = ${wildcard $(TOP_DIR)/targets/STM32L431_BearPi/Demos/sal_test_demo/sal_tcp_demo.c}
	endif

位置如下:

LiteOS的SAL及socket編程方法是什么

最后在.sdkconfig中配置選中該demo文件:

LiteOS的SAL及socket編程方法是什么

然后編譯,下載,即可看到串口輸出(前提是確保TCP服務器已開啟):

LiteOS的SAL及socket編程方法是什么

在TCP服務端軟件也可以看到:

LiteOS的SAL及socket編程方法是什么

在服務端發送數據,在串口可以看到客戶端已接收:

LiteOS的SAL及socket編程方法是什么

5. UDP Socket客戶端編程實例

5.1. UDP服務端的建立

在本實驗中,UDP Server使用網絡調試助手模擬,在本機8000端口開啟一個UDP服務器,如圖:

LiteOS的SAL及socket編程方法是什么

5.2. SAL提供的Socket客戶端編程API

連接服務器socket

API原型如下:

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

參數說明如下:

參數說明
sockfd創建成功的sockfd描述符
addrsockaddr結構體指針
addrlensockaddr結構體長度

發送數據

API原型如下:

int sal_sendto(int sockfd, const void *dataptr, size_t size, int flags,
    const struct sockaddr *to, socklen_t tolen);

參數說明如下:

參數說明
sockfd創建成功的sockfd描述符
dataptr待發送的數據指針
size發送包數據大小
flags發送或接收標記,一般都設為0
addrsockaddr結構體指針
addrlensockaddr結構體長度

接收數據

API原型如下:

int sal_recvfrom(int sockfd, void *mem, size_t len, int flags,
      struct sockaddr *from, socklen_t *fromlen);

參數說明如下:

參數說明
sockfd創建成功的sockfd描述符
mem接收緩沖區數據指針
size接收數據大小
flags發送或接收標記,一般都設為0
addrsockaddr結構體指針
addrlensockaddr結構體長度

關閉socket

API原型如下:

int sal_closesocket(int sockfd);

參數說明如下:

參數說明
sockfd創建成功的sockfd描述符

5.3. 基于SAL的UDP客戶端編程

打開之前創建的HelloWorld工程(如果沒有,可以參考第一篇教程新建),創建下面的文件夾sal_test_demo,并在該文件夾中新建一個測試文件sal_udp_demo.c

LiteOS的SAL及socket編程方法是什么

編輯以下內容:

注意,其中的server_ip和server_port應該是服務器的實際情況相對應!

#include <osal.h>
#include <sal.h>

#define server_port 8000
#define server_ip   "192.168.0.101"

static int sal_udp_demo_entry()
{
    int sockfd;

    /* 創建udp socket */
    sockfd = sal_socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd < 0)
    {
        printf("udp Socket create fail.\r\n");
        return -1;
    }
    else
    {
        printf("udp Socket create ok.\r\n");
    }

    /* 服務端信息 */
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(server_port);
    server_addr.sin_addr.s_addr = inet_addr(server_ip);

    /* 發送數據到服務器 */
    int nbytes;
    char buf[] = "hello server!";
    nbytes = sal_sendto(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&server_addr, sizeof(struct sockaddr));
    if(nbytes < 0)
    {
        printf("send dat %s fail.\r\n", buf);
        return -1;
    }
    else
    {
        printf("send [%d] bytes: %s.\r\n", nbytes , buf);
    }

    /* 等待接收服務器數據 */
    char recv_buf[50]={0};
    while( -1 == (nbytes = sal_recvfrom(sockfd, recv_buf, 50, 0,  (struct sockaddr*)&server_addr, sizeof(struct sockaddr))));
    printf("recv [%d] bytes: %s.\r\n", nbytes, recv_buf);

    /* 關閉socket */
    sal_closesocket(sockfd);
    printf("udp socket closed.\r\n");

    return 0;
}

int standard_app_demo_main()
{
    osal_task_create("sal_udp_demo",sal_udp_demo_entry,NULL,0x800,NULL,12);
    return 0;
}

然后在user_demo.mk中添加文件路徑:

	#example for sal_udp_demo
	ifeq ($(CONFIG_USER_DEMO), "sal_udp_demo")	
		user_demo_src  = ${wildcard $(TOP_DIR)/targets/STM32L431_BearPi/Demos/sal_test_demo/sal_udp_demo.c}
	endif

位置如下:

LiteOS的SAL及socket編程方法是什么

最后在.sdkconfig中配置選中該demo文件:

LiteOS的SAL及socket編程方法是什么

然后編譯,下載,即可看到串口輸出(前提是確保UDP服務器已開啟):

LiteOS的SAL及socket編程方法是什么

在UDP服務端軟件也可以看到:

LiteOS的SAL及socket編程方法是什么

在服務端發送數據,在串口可以看到客戶端已接收:

LiteOS的SAL及socket編程方法是什么

感謝各位的閱讀,以上就是“LiteOS的SAL及socket編程方法是什么”的內容了,經過本文的學習后,相信大家對LiteOS的SAL及socket編程方法是什么這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

浏阳市| 察隅县| 阳信县| 桦甸市| 镇平县| 五台县| 龙川县| 华容县| 南漳县| 蒙阴县| 唐河县| 秦皇岛市| 沙洋县| 大名县| 佳木斯市| 桦南县| 涞源县| 宝兴县| 安图县| 澎湖县| 长乐市| 谷城县| 泰兴市| 黎川县| 加查县| 长顺县| 全南县| 宣汉县| 收藏| 高平市| 恩施市| 百色市| 庆城县| 盐津县| 习水县| 许昌县| 湖北省| 彩票| 怀柔区| 雅安市| 临颍县|