本篇博客简单的来看一下CoAP_socket
部分。
还是从头文件开始看起,首先是两个宏定义:
1 2
| #define COAP_DEFAULT_PORT 5684 #define COAP_MAX_PDU_SIZE 1024
|
- 从命名可以看出,我们的 CoAP 协议默认是运行在UDP的 5684 端口上
- 另一个宏定义限制了 CoAP 协议每个数据包的最大长度
另外还定义了一个结构体用于记录 socket 的信息:
1 2 3 4
| typedef struct { int cliendFd; struct sockaddr_in dstAddr; } SocketInfo;
|
最后还定义了 7 个函数对外提供相关的服务:
1 2 3 4 5 6 7
| 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);
|
GetCoapServerSocket
GetCoapClientSocket
CoapInitSocket
- 调用
CoapCreateUdpServer
初始化服务端
CoapCreateUdpClient
CoapCreateUdpServer
- 服务端创建 socket 并绑定端口,等待客户端连接
CoapSocketRecv
CoapSocketSend
其中GetCoapServerSocket
和GetCoapClientSocket
返回的是一个全局的套接字描述符:
1 2 3 4 5 6 7 8 9 10 11 12
| int g_serverFd = -1; int g_clientFd = -1;
int GetCoapServerSocket(void) { return g_serverFd; }
int GetCoapClientSocket(void) { return g_clientFd; }
|
下面是服务端的CoapInitSocket
调用CoapCreateUdpServer
创建 socket 并绑定端口,等待客户端连接:
CoapInitSocket
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| int CoapInitSocket(void) { if (g_serverFd >= 0) { return NSTACKX_EOK; } struct sockaddr_in sockAddr; (void)memset_s(&sockAddr, sizeof(sockAddr), 0, sizeof(sockAddr)); sockAddr.sin_port = htons(COAP_DEFAULT_PORT); g_serverFd = CoapCreateUdpServer(&sockAddr); if (g_serverFd < 0) { return NSTACKX_OVERFLOW; } COAP_SoftBusInitMsgId(); return NSTACKX_EOK; }
|
- 第 8 行写入了默认的端口号 5684 :
sockAddr.sin_port = htons(COAP_DEFAULT_PORT);
- 紧接着第 9 行调用了
CoapCreateUdpServer
创建 socket 并把描述符赋值给全局变量g_serverFd
CoapCreateUdpServer
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| 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.sin_family = AF_INET; localAddr.sin_port = sockAddr->sin_port; if (sockAddr->sin_addr.s_addr != 0) { localAddr.sin_addr.s_addr = sockAddr->sin_addr.s_addr; } else { localAddr.sin_addr.s_addr = htonl(INADDR_ANY); }
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; }
|
- 第 9 行创建了一个 socket 并拿到了描述符:
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- 第 23 行把 socket 与端口进行了绑定:
bind(sockfd, (struct sockaddr *)&localAddr, len)
另外sockaddr
的定义是:
1 2 3 4
| struct sockaddr { sa_family_t sin_family; char sa_data[14]; };
|
上面说完了服务端的,现在来看到客户端的:
CoapCreateUdpClient
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| int CoapCreateUdpClient(const struct sockaddr_in *sockAddr) { 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; }
|
- 同样的,在第 8 行创建了一个 socket :
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
- 随后使用获得的 socket 对指定地址进行尝试连接:
int ret = connect(sockfd, (struct sockaddr *)sockAddr, sizeof(struct sockaddr));
- 最后是对连接的状态进行检查,若发送错误则会调用
CloseSocket(&sockfd);
关闭对应的 socket 并返回错误值。
最后来看到数据的收发:
CoapSocketSend
:
1 2 3 4 5 6 7 8 9 10
| 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); return ret; }
|
CoapSocketRecv
:
1 2 3 4 5 6 7 8 9 10 11 12
| 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); return ret; }
|
都是根据传入的描述符socketFd
、存放数据的缓冲区buffer
、数据长度length
,分别调用sendto
和recvfrom
进行数据的收发。