IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> OpenHarmony源码评注|coap_socket套接字解析 -> 正文阅读

[网络协议]OpenHarmony源码评注|coap_socket套接字解析

在“OpenHarmony源码评注|Coap协议的定义”中,我们具体讲了coap协议的定义方法并补充了Coap协议的特点。本篇我们主要讲如何传输Coap数据包。

背景知识

套接字(Socket),是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端。数据传输时,会有服务器端和客户端双向通信,通过两端的套接字进行数据收发工作。

源码分析

在communication_softbus_lite-master\discovery\coap?中定义了coap_socket.h头文件,提供了COAP包的发送和接收服务函数

#define COAP_DEFAULT_PORT      5684   //在此端口提供监听COAP包的服务

typedef struct {
    int cliendFd;                     
    struct sockaddr_in dstAddr;       //目的地址
} SocketInfo;

int GetCoapServerSocket(void);        //获取服务器套接字
int GetCoapClientSocket(void);        //获取客户端套接字
int CoapInitSocket(void);             //初始化端口的功能
int CoapCreateUdpClient(const struct sockaddr_in *sockAddr);     //创建一个服务器
int CoapCreateUdpServer(const struct sockaddr_in *sockAddr);     //创建一个客户端
int CoapSocketRecv(int socketFd, uint8_t *buffer, size_t length);//发送数据
int CoapSocketSend(const SocketInfo *socket, const uint8_t *buffer, size_t length);  //接收数据
#define COAP_MAX_PDU_SIZE 1024        //协议数据单元大小

实现传输的过程大致分为三步:创建服务器和客户端,两端连接,数据传输

在coap_socket.c中具体实现了所有功能

创建服务器

int CoapCreateUdpServer(const struct sockaddr_in *sockAddr)   //创建服务器,传输协议为UDP
{
    if (sockAddr == NULL) {
        return NSTACKX_EINVAL;                    //判断传入地址是否为空,若空返回无效
    }

    struct sockaddr_in localAddr;                 //创建本地地址结构体
    socklen_t len = sizeof(localAddr);            //获得地址大小
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);  //建立一个socket用于连接
    if (sockfd < 0) {
        return NSTACKX_OVERFLOW;                  //判断创建是否成功
    }

    (void)memset_s(&localAddr, sizeof(localAddr), 0, sizeof(localAddr));    
    localAddr.sin_family = AF_INET;               //保存地址族
    localAddr.sin_port = sockAddr->sin_port;      //存放sock地址
    if (sockAddr->sin_addr.s_addr != 0) {         //如果sock地址部位0
        localAddr.sin_addr.s_addr = sockAddr->sin_addr.s_addr;    //将sock地址存入本地
    } else {
        localAddr.sin_addr.s_addr = htonl(INADDR_ANY);            //s_addr为0,则localAttr对应的s_addr为htonl获取的地址
    }

    if (bind(sockfd, (struct sockaddr *)&localAddr, len) == -1) { //将sockfd和localAddr相关联的端口设备进行绑定
        CloseSocket(&sockfd);                                     //失败则关闭套接字,返回失败信息
        return NSTACKX_EFAILED;
    }

    if (getsockname(sockfd, (struct sockaddr *)&localAddr, &len) == -1) { //获取套接字的名字
        CloseSocket(&sockfd);                                             //失败则关闭套接字
        return NSTACKX_EFAILED;
    }
    return sockfd;                                                        //返回套接字
}

创建客户端

int CoapCreateUdpClient(const struct sockaddr_in *sockAddr)              //创建客户端,协议为UDP
{
    if (sockAddr == NULL) {
        return NSTACKX_EFAILED;                                          //判断传入地址是否为空
    }

    struct sockaddr_in tmpAddr;                                          //创建临时套接字地址
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);                         //创建一个新的套接字
    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;                                                  //返回创建成功
}

其中connect函数负责将服务器与客户端连接

int ret = connect(sockfd, (struct sockaddr *)sockAddr, sizeof(struct sockaddr)); //将服务端与客户端连接
    if (ret != 0) {                                                                  //判断连接是否成功
        CloseSocket(&sockfd);                                                        //失败则关闭,返回错误信息
        return NSTACKX_EFAILED;
    }

?初始化

int CoapInitSocket(void)                    //初始化套接字
{
    if (g_serverFd >= 0) {                  //检查是否已经建立连接
        return NSTACKX_EOK;
    }
    struct sockaddr_in sockAddr;            //创建一个网络通信地址sockAddr
    (void)memset_s(&sockAddr, sizeof(sockAddr), 0, sizeof(sockAddr)); //对sockAddr初始化
    sockAddr.sin_port = htons(COAP_DEFAULT_PORT); //将多字节整数类型的数据,从主机的字节顺序转化为网络字节顺序
    g_serverFd = CoapCreateUdpServer(&sockAddr);  //创建服务器,获取套接字
    if (g_serverFd < 0) {
        return NSTACKX_OVERFLOW;                  //判断套接字是否有效
    }
    COAP_SoftBusInitMsgId();   //COAP_SoftBusInitMsgId函数把全局变量g_msgId初始化为常量RAND_DIVISOR,做为COAP协议中的MessageID
    return NSTACKX_EOK;        //返回成功

初始化连接的逻辑就是先判断服务器是否已经存在,若存在说明已经建立连接了,直接返回;

若没有建立连接,则创建通信地址,创建服务器

数据收发

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;
}

CoapSocketSend函数用来将数据发送到udp连接的另一端

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));
    int ret = recvfrom(socketFd, buffer, length, 0, (struct sockaddr *)&addr, &len);
    //recvfrom函数用来接收指定socket传来的数据
    return ret;
}

CoapSocketRecv函数则负责数据接收

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-09-05 11:23:21  更:2021-09-05 11:25:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年6日历 -2024/6/27 1:37:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码