文章目录
coap_socket.c代码分析
本篇主题:本篇博客主要分析coap_socket.c相关代码
文件路径(软总线模块\discovery\coap\source\coap_socket.c)
一、背景知识
二、coap_socket.c代码详细分析
该文件中主要分为三部分,分别为套接字的获取,socket两端(客户端、服务器)的创建,数据的发送和接收。
2.1 套接字的获取
这一部分主要使用函数来返回用户定义的全局变量g_serverFd、g_clientFd。实现套接字的获取
int g_serverFd = -1;//全局服务器套接字
int g_clientFd = -1;//客户端套接字
//用来获取coap服务器的套接字g_serverFd
int GetCoapServerSocket(void)
{
return g_serverFd;
}
//用来获取coap客户端的套接字g_clientFd
int GetCoapClientSocket(void)
{
return g_clientFd;
}
2.2 socket两端(客户端、服务器)的创建
下面两部分代码主要实现客户端的创建和服务器的创建。
基于udp协议服务器的创建
该函数主要用来创建一个基于udp协议的服务器,而非trans_service下面的TCP协议。
实现套接字的创建和端口绑定(bind())的过程。
//创建一个服务器,传输协议为udp而非tcp
int CoapCreateUdpServer(const struct sockaddr_in *sockAddr)
{
if (sockAddr == NULL) {
return NSTACKX_EINVAL;
//检查传入的啊承诺书是否为空
}
struct sockaddr_in localAddr;//本地地址结构体
socklen_t len = sizeof(localAddr);//
int sockfd = socket(AF_INET, SOCK_DGRAM, 0); //创建一个套接字
if (sockfd < 0) {
return NSTACKX_OVERFLOW;
}
(void)memset_s(&localAddr, sizeof(localAddr), 0, sizeof(localAddr));
//对localAddr进行初始化
localAddr.sin_family = AF_INET; //用来保存本地的地址族
localAddr.sin_port = sockAddr->sin_port;//存放sock地址的端口
if (sockAddr->sin_addr.s_addr != 0) {
//如果端口的s_addr不为0
localAddr.sin_addr.s_addr = sockAddr->sin_addr.s_addr;
//将sockaddr的s_addr写进localAttr
} else {
//s_addr为0,则localAttr对应的s_addr为htonl获取的地址
localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
}
//将sockfd和localAddr相关联的端口设备进行绑定
if (bind(sockfd, (struct sockaddr *)&localAddr, len) == -1) {
CloseSocket(&sockfd);
//绑定失败就关闭套接字
return NSTACKX_EFAILED;
}
if (getsockname(sockfd, (struct sockaddr *)&localAddr, &len) == -1) {
//获取套接字的名字,获取失败就关闭套接字
CloseSocket(&sockfd);
return NSTACKX_EFAILED;
}
return sockfd;//最后返回所连接套接字
}
基于udp协议的客户端创建
该函数主要用来创建一个基于udp协议的客户端,中间使用到临时地址,最后将创建成功的服务器套接字写进定义的全局变量g_clientFd。
//和上方创建服务器类似,这里创建一个客户端
int CoapCreateUdpClient(const struct sockaddr_in *sockAddr)
{
if (sockAddr == NULL) {
return NSTACKX_EFAILED;
//用来检查传入的sockAddr
}
struct sockaddr_in tmpAddr;//定义一个临时的套接字地址
int sockfd = socket(AF_INET, SOCK_DGRAM, 0); //创建生成一个新的套接字sockfd
if (sockfd < 0) {
return NSTACKX_EFAILED;
//创建失败的处理
}
int ret = connect(sockfd, (struct sockaddr *)sockAddr, sizeof(struct sockaddr));
//根据所创建生成的套接字进行连接
if (ret != 0) {
CloseSocket(&sockfd);
return NSTACKX_EFAILED;
//连接失败关闭套接字,函数返回
}
socklen_t srcAddrLen = sizeof(struct sockaddr_in);
(void)memset_s(&tmpAddr, sizeof(tmpAddr), 0, sizeof(tmpAddr));
//初始化临时的套接字地址,并获取临时套接字名字
ret = getsockname(sockfd, (struct sockaddr *)&tmpAddr, &srcAddrLen);
if (ret != 0) {
CloseSocket(&sockfd);
return NSTACKX_EFAILED;
//获取失败的处理
}
CloseSocket(&g_clientFd);
//关闭临时客户端
g_clientFd = sockfd;
//并且将客户端套接字重置为新生成的套接字
return NSTACKX_EOK;
}
2.3 数据的接收和发送
发送数据基于CoapSocketSend()函数
该函数的主要原理是将数据传送至指定目的缓冲区,可以实现未连接状态下的数据发送。这里主要是发送到socket->dstAddr对应的目的地缓冲区
sendto()函数参数详解:
- s 套接字
- buff 待发送数据的缓冲区
- size 缓冲区长度
- Flags 调用方式标志位, 一般为0, 改变Flags,将会改变Sendto发送的形式
- addr (可选)指针,指向目的套接字的地址
- len addr所指地址的长度
//用来将数据发送到udp连接的另一端
int CoapSocketSend(const SocketInfo *socket, const uint8_t *buffer, size_t length)
{
if (buffer == NULL || socket == NULL) {
return NSTACKX_EFAILED;
}
socklen_t dstAddrLen = sizeof(struct sockaddr_in);
int ret = sendto(socket->cliendFd, buffer, length, 0, (struct sockaddr *)&socket->dstAddr, dstAddrLen);
//sendto用来发送udp数据包,这里发送到ocket->dstAddr目的地缓冲区
return ret;
}
接收数据基于CoapSocketRecv()函数
该函数主要实现数据的接收,基于recvfrom()函数接收远程主机经指定的socket传来的数据,并把数据传到由参数buf指向的内存空间,参数len为可接收数据的最大长度.参数flags一般设0,其他数值定义参考recv().参数from用来指定欲传送的网络地址,结构sockaddr请参考bind()函数.参数fromlen为sockaddr的结构长度。
recvfrom()函数参数详解:
- socketfd 套接字
- buffer 存放接收的数据
- len 可接收数据的最大长度
//用来接收数据经过socket
int CoapSocketRecv(int socketFd, uint8_t *buffer, size_t length)
{
if (buffer == NULL || socketFd < 0) {
return NSTACKX_EFAILED;
//参数检查
}
struct sockaddr_in addr;
socklen_t len = sizeof(struct sockaddr_in);
(void)memset_s(&addr, sizeof(addr), 0, sizeof(addr));
//初始化addr缓冲区
int ret = recvfrom(socketFd, buffer, length, 0, (struct sockaddr *)&addr, &len);
//recvfrom函数用来接收指定socket传来的数据
return ret;
}
三、总结
以上就是coap_socket.c的内容,简单介绍了该文件中代码结构和原理。感谢阅读和点赞。