一、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 */