工作原理

SAL 组件主要实现的两个功能:支持多个协议栈接入和统一抽象接口函数。对于不同的协议栈或网络功能实现,网络接口的名称可能各不相同,以 connect 连接函数为例,lwIP 协议栈中接口名称为 lwip_connect ,而 AT Socket 网络实现中接口名称为 at_connect。SAL 组件提供对不同协议栈或网络实现接口的抽象和统一,组件在 socket 创建时通过判断传入的协议簇(domain)类型来判断使用的协议栈或网络功能,完成 RT-Thread 系统中多协议的接入与使用。

  1. int socket(int domain, int type, int protocol);

上述为标准 BSD Socket API 中 socket 创建函数的定义,其中 domain 表示协议域又称为协议簇(family),用于判断使用哪种协议栈或网络实现,AT Socket 网络实现的协议簇类型为 AF_AT,lwIP 协议栈使用协议簇类型有 AF_INETAF_INET6 等。开启 lwIP 协议栈支持后,使用 AF_INET 创建网络套接字,则此套接字底层使用 lwIP 协议栈函数实现。AT Socket 是 RT-Thread 自主研发的基于 AT 组件的网络功能实现,其设备的连接和数据的通讯都是通过 AT 命令完成,支持标准 BSD Socket API 。

目前 RT-Thread 系统中网络软件包或网络功能的 socket 创建函数中协议簇类型固定,若要支持不同的协议栈或网络实现需要修改传入的协议簇类型。为了适配不同协议栈或网络实现,SAL 组件中对于每个协议栈或者网络实现提供两种协议簇类型匹配方式:主协议簇类型和次协议簇类型。socket 创建时先判断传入协议簇类型是否存在已经支持的主协议类型,如果是则使用对应协议栈或网络实现,如果不是判断次协议簇类型是否支持。目前系统支持协议簇类型如下:

  1. lwIP 协议栈: family = AF_INETsec_family = AF_INET
  2. AT Socket 网络实现: family = AF_ATsec_family = AF_INET

对于 SAL 组件中协议簇的支持,组件中每个协议簇类型存在一个协议簇结构体,由协议簇结构体列表统一管理,协议簇结构体中定义了该协议栈的执行函数,如 lwIP 协议栈中的 lwip_socket()、lwip_connect() 等。 SAL 组件中创建的每个 socket 也存在结构体定义,由 socket 结构体列表统一管理,socket 结构体中存放当前 socket 的执行函数和基本信息,在 socket 创建时通过判断传入协议簇类型,注册对应协议簇执行函数到 socket 结构体执行函数中。之后,使用该 socket 进行函数操作时,主要是获取 socket 结构体中的协议簇执行函数,完成函数操作。如下为 SAL 组件中 connect 函数抽象实现示例:

  1. /* SAL 组件为应用层提供的标准 BSD Socket API */
  2. int connect(int s, const struct sockaddr _name, socklen_t namelen){
  3. /* 获取 SAL 套接字描述符 */
  4. int socket = dfs_net_getsocket(s);
  5.  
  6. /* 通过 SAL 套接字描述符执行 sal_connect 函数 */
  7. returnsal_connect(socket,name,namelen);
  8. }
  9.  
  10. /* SAL 组件抽象函数接口实现 */
  11. int sal_connect(int socket, const struct sockaddr _name, socklen_t namelen){
  12. struct socket _sock;
  13.  
  14.  
  15. /* 通过 SAL 套接字描述符获取 socket 结构体 */
  16. sock=sal_get_socket(socket);
  17. if(!sock)
  18. {
  19. return-1;
  20. }
  21.  
  22. if(sock->ops->connect==RT_NULL)
  23. {
  24. return-RT_ENOSYS;
  25. }
  26.  
  27. /* 调用获取结构体中对应的协议簇执行函数 */
  28. returnsock->ops->connect((int)sock->user_data,name,namelen);
  29.  
  30. }
  31.  
  32. /* 协议簇执行函数调用底层 lwIP 协议栈函数实现 */
  33. int lwip_connect(int socket, const struct sockaddr *name, socklen_t namelen){ ...}