【rtthread番外】第三篇:套接字抽象层SAL

一、SAL概念

SAL是rtthread提供的socket组件,将底层不同协议栈统一为上层提供标准的BSD Socket api。
在这里插入图片描述

二、SAL api

//创建套接字
/*
domain:协议簇类型
type:协议类型
protocol:运输层协议
返回:套件字描述符
*/
int socket(int domain, int type, int protocol);

//绑定套接字,将端口号和IP绑定到套接字上
/*
s:套接字描述符
name:要绑定的地址,依赖netdev组件
namelen: sockaddr结构体的长度
*/
int bind(int s, const struct sockaddr *name, socklen_t namelen);

//监听套接字,用于服务器监听指定套接字的连接
/*
s:套接字描述符
backlog:一次能够等待的最大连接数
*/
int listen(int s, int backlog);

//接收连接,当监听到连接时,使用accept为连接创建新套接字并将连接移除出监听队列
/*
s:套接字描述符
addr:
addrlen:
返回:新套接字描述符
*/
int accept(int s, struct sockaddr *addr, socklen_t *addrlen);

//建立连接,建立连接后创建新套接字
/*
s:套接字描述符
name:服务器地址信息
namelen:服务器地址结构体长度
返回:新套接字描述符
*/
int connect(int s, const struct sockaddr *name, socklen_t namelen);

//TCP发送数据
/*
s:套接字描述符
datapr:发送缓冲区
size:发送数据大小
flags:标志,一般为0
*/
int send(int s, const void *dataptr, size_t size, int flags);

//TCP接收数据
/*
s:套接字描述符
mem:接收缓冲区
len:接收数据大小
flags:标志,一般为0
*/
int recv(int s, void *mem, size_t len, int flags);

//UDP发送
/*
s:套接字描述符
datapr:发送缓冲区
size:发送大小
flags:标志,一般为0
to:目标套接字地址
tolen:目标地址信息结构体大小
*/
int sendto(int s, const void *dataptr, size_t size, int flags, const struct sockaddr *to, socklen_t tolen);

//UDP接收
/*
s:套接字描述符
mem:接收缓冲区
len:接收数据大小
flags:标志,一般为0
from:来自哪个套接字
fromlen:套接字信息结构体大小
*/
int recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);

//关闭套接字
/*
s:套接字描述符
*/
int closesocket(int s);

//按设置关闭套接字
/*
s:套接字描述符
how:怎样关闭套接字,可取
     0:停止接收当前数据,并拒绝以后的数据接收;

    1:停止发送数据,并丢弃未发送的数据;

    2:停止接收和发送数据。
*/
int shutdown(int s, int how);

//设置套接字选项
/*
s:套接字描述符
level:协议栈配置选项
optname:选项名
optval:存放选项值的指针
optlen:选项值长度
*/
int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);

//获取套接字选项
/*
s:套接字描述符
level:配置哪个协议栈
optname:选项名
optval:存放选项值的指针
optlen:选项值长度
*/
int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen);

//获取远端地址信息
/*
s:套接字描述符
name:接收信息的地址结构体指针
namelen:地址结构体大小
*/
int getpeername(int s, struct sockaddr *name, socklen_t *namelen);

//获取本地地址信息
/*
s:套接字描述符
name:接收信息的地址结构体指针
namelen:地址结构体大小
*/
int getsockname(int s, struct sockaddr *name, socklen_t *namelen);

//配置套接字参数
/*
s:套接字描述符
cmd:套接字操作命令,可取
     FIONBIO:开启或关闭套接字的非阻塞模式, arg 参数 1 为开启非阻塞, 0 为关闭非阻塞
arg:命令参数
*/
int ioctlsocket(int s, long cmd, void *arg);

三、SAL注册示例

该示例展示将AT Socket的底层socket api注册到rtthread的sal套接字抽象层。

#include <rtthread.h>
#include <netdb.h>
#include <sal.h> /* SAL 组 件 结 构 体 存 放 头 文 件 */
#include <at_socket.h> /* AT Socket 相 关 头 文 件 */
#include <af_inet.h>
#include <netdev.h> /* 网 卡 功 能 相 关 头 文 件 */
#ifdef SAL_USING_POSIX
#include <dfs_poll.h> /* poll 函 数 实 现 相 关 头 文 件 */
#endif
#ifdef SAL_USING_AT
/* 自 定 义 的 poll 执 行 函 数, 用 于 poll 中 处 理 接 收 的 事 件 */
static int at_poll(struct dfs_fd *file, struct rt_pollreq *req)
{
    
    
	int mask = 0;
	struct at_socket *sock;
	struct socket *sal_sock;
	sal_sock = sal_get_socket((int) file->data);
	if(!sal_sock)
	{
    
    
		return -1;
	}
	sock = at_get_socket((int)sal_sock->user_data);
	if (sock != NULL)
	{
    
    
		rt_base_t level;
		rt_poll_add(&sock->wait_head, req);
		level = rt_hw_interrupt_disable();
		if (sock->rcvevent)
		{
    
    
			mask |= POLLIN;
		}
		if (sock->sendevent)
		{
    
    
			mask |= POLLOUT;
		}
		if (sock->errevent)
		{
    
    
			mask |= POLLERR;
		}
		rt_hw_interrupt_enable(level);
	}
	return mask;
} #
endif
/* 定 义 和 赋 值 Socket 执 行 函 数, SAL 组 件 执 行 相 关 函 数 时 调 用 该 注 册 的 底 层 函 数 */
static const struct proto_ops at_inet_stream_ops =
{
    
    
	at_socket,
	at_closesocket,
	at_bind,
	NULL,
	at_connect,
	NULL,
	at_sendto,
	at_recvfrom,
	at_getsockopt,
	at_setsockopt,
	at_shutdown,
	NULL,
	NULL,
	NULL,
	#ifdef SAL_USING_POSIX
	at_poll,
	#else
	NULL,
	#endif /* SAL_USING_POSIX */
};
static const struct sal_netdb_ops at_netdb_ops =
{
    
    
	at_gethostbyname,
	NULL,
	at_getaddrinfo,
	at_freeaddrinfo,
};
/* 定 义 和 赋 值 AT Socket 协 议 簇 结 构 体 */
static const struct sal_proto_family at_inet_family =
{
    
    
	AF_AT,
	AF_INET,
	&at_socket_ops,
	&at_netdb_ops,
};
/* 用 于 设 置 网 卡 设 备 中 协 议 簇 相 关 信 息 */
int sal_at_netdev_set_pf_info(struct netdev *netdev)
{
    
    
	RT_ASSERT(netdev);
	netdev->sal_user_data = (void *) &at_inet_family;
	return 0;
} #
endif /* SAL_USING_AT */

Guess you like

Origin blog.csdn.net/weixin_43810563/article/details/117135959