platformNetwork.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. #define rlogLevel (rlogLvlDebug) // 日志打印等级
  2. #include "platformNetwork.h"
  3. #include "RyanMqttLog.h"
  4. /**
  5. * @brief 初始化网络接口层
  6. *
  7. * @param userData
  8. * @param platformNetwork
  9. * @return RyanMqttError_e
  10. */
  11. RyanMqttError_e platformNetworkInit(void *userData, platformNetwork_t *platformNetwork)
  12. {
  13. platformNetwork->socket = -1;
  14. return RyanMqttSuccessError;
  15. }
  16. /**
  17. * @brief 销毁网络接口层
  18. *
  19. * @param userData
  20. * @param platformNetwork
  21. * @return RyanMqttError_e
  22. */
  23. RyanMqttError_e platformNetworkDestroy(void *userData, platformNetwork_t *platformNetwork)
  24. {
  25. platformNetwork->socket = -1;
  26. return RyanMqttSuccessError;
  27. }
  28. /**
  29. * @brief 连接mqtt服务器
  30. *
  31. * @param userData
  32. * @param platformNetwork
  33. * @param host
  34. * @param port
  35. * @return RyanMqttError_e
  36. * 成功返回RyanMqttSuccessError, 失败返回错误信息
  37. */
  38. RyanMqttError_e platformNetworkConnect(void *userData, platformNetwork_t *platformNetwork, const char *host,
  39. uint16_t port)
  40. {
  41. RyanMqttError_e result = RyanMqttSuccessError;
  42. char *buf = NULL;
  43. struct sockaddr_in server_addr = {
  44. .sin_family = AF_INET,
  45. .sin_port = htons(port), // 指定端口号
  46. };
  47. // 传递的是ip地址,不用进行dns解析,某些情况下调用dns解析反而会错误
  48. if (INADDR_NONE != inet_addr(host))
  49. {
  50. rlog_d("host: %s, 不用dns解析", host);
  51. server_addr.sin_addr.s_addr = inet_addr(host);
  52. }
  53. // 解析域名信息
  54. else
  55. {
  56. #define dnsBufferSize (384)
  57. rlog_d("host: %s, 需要dns解析", host);
  58. int h_errnop;
  59. struct hostent *phost;
  60. struct hostent hostinfo = {0};
  61. buf = (char *)platformMemoryMalloc(dnsBufferSize);
  62. if (NULL == buf)
  63. {
  64. result = RyanMqttNoRescourceError;
  65. goto __exit;
  66. }
  67. if (0 != gethostbyname_r(host, &hostinfo, buf, dnsBufferSize, &phost, &h_errnop))
  68. {
  69. rlog_w("平台可能不支持 gethostbyname_r 函数, 再次尝试使用 gethostbyname 获取域名信息");
  70. // 非线程安全版本,请根据实际情况选择使用
  71. // NOLINTNEXTLINE(concurrency-mt-unsafe)
  72. struct hostent *phostinfo = gethostbyname(host);
  73. if (NULL == phostinfo)
  74. {
  75. result = RyanMqttNoRescourceError;
  76. goto __exit;
  77. }
  78. hostinfo = *phostinfo;
  79. }
  80. server_addr.sin_addr = *((struct in_addr *)hostinfo.h_addr_list[0]);
  81. }
  82. platformNetwork->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
  83. if (platformNetwork->socket < 0)
  84. {
  85. result = RyanSocketFailedError;
  86. goto __exit;
  87. }
  88. // 绑定套接字到主机地址和端口号
  89. if (connect(platformNetwork->socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0)
  90. {
  91. platformNetworkClose(userData, platformNetwork);
  92. result = RyanMqttSocketConnectFailError;
  93. goto __exit;
  94. }
  95. __exit:
  96. if (NULL != buf)
  97. {
  98. platformMemoryFree(buf);
  99. }
  100. if (RyanMqttSuccessError != result)
  101. {
  102. rlog_e("socket连接失败: %d", result);
  103. }
  104. return result;
  105. }
  106. /**
  107. * @brief 非阻塞接收数据
  108. *
  109. * @param userData
  110. * @param platformNetwork
  111. * @param recvBuf
  112. * @param recvLen
  113. * @param timeout
  114. * @return RyanMqttError_e
  115. * socket错误返回 RyanSocketFailedError
  116. * 接收超时或者接收数据长度不等于期待数据接受长度 RyanMqttRecvPacketTimeOutError
  117. * 接收成功 RyanMqttSuccessError
  118. */
  119. int32_t platformNetworkRecvAsync(void *userData, platformNetwork_t *platformNetwork, char *recvBuf, size_t recvLen,
  120. int32_t timeout)
  121. {
  122. ssize_t recvResult = 0;
  123. struct timeval tv = {
  124. .tv_sec = timeout / 1000,
  125. .tv_usec = 1000 * timeout % 1000,
  126. };
  127. if (-1 == platformNetwork->socket)
  128. {
  129. rlog_e("对端关闭socket连接");
  130. return -1;
  131. }
  132. setsockopt(platformNetwork->socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,
  133. sizeof(struct timeval)); // 设置操作模式为非阻塞
  134. recvResult = recv(platformNetwork->socket, recvBuf, recvLen, 0);
  135. if (0 == recvResult)
  136. {
  137. rlog_e("对端关闭socket连接");
  138. return -1;
  139. }
  140. if (recvResult < 0) // 小于零,表示错误,个别错误不代表socket错误
  141. {
  142. int32_t rt_errno = errno; // 似乎RT 5.0.0以上版本需要使用 rt_get_errno
  143. // 下列表示没问题,但需要退出接收
  144. if (EAGAIN == rt_errno || // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
  145. EWOULDBLOCK == rt_errno || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
  146. EINTR == rt_errno || // 操作被信号中断
  147. ETIME == rt_errno) // 计时器过期
  148. {
  149. return 0;
  150. }
  151. // NOLINTNEXTLINE(concurrency-mt-unsafe)
  152. rlog_e("recvResult: %d, errno: %d str: %s", recvResult, rt_errno, strerror(rt_errno));
  153. return -1;
  154. }
  155. return (int32_t)recvResult;
  156. }
  157. /**
  158. * @brief 非阻塞发送数据
  159. *
  160. * @param userData
  161. * @param platformNetwork
  162. * @param sendBuf
  163. * @param sendLen
  164. * @param timeout
  165. * @return RyanMqttError_e
  166. * socket错误返回 RyanSocketFailedError
  167. * 接收超时或者接收数据长度不等于期待数据接受长度 RyanMqttRecvPacketTimeOutError
  168. * 接收成功 RyanMqttSuccessError
  169. */
  170. int32_t platformNetworkSendAsync(void *userData, platformNetwork_t *platformNetwork, char *sendBuf, size_t sendLen,
  171. int32_t timeout)
  172. {
  173. ssize_t sendResult = 0;
  174. struct timeval tv = {
  175. .tv_sec = timeout / 1000,
  176. .tv_usec = 1000 * timeout % 1000,
  177. };
  178. if (-1 == platformNetwork->socket)
  179. {
  180. rlog_e("对端关闭socket连接");
  181. return -1;
  182. }
  183. setsockopt(platformNetwork->socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv,
  184. sizeof(struct timeval)); // 设置操作模式为非阻塞
  185. sendResult = send(platformNetwork->socket, sendBuf, sendLen, 0);
  186. if (0 == sendResult)
  187. {
  188. rlog_e("对端关闭socket连接");
  189. return -1;
  190. }
  191. if (sendResult < 0) // 小于零,表示错误,个别错误不代表socket错误
  192. {
  193. int32_t rt_errno = errno; // 似乎5.0.0以上版本需要使用 rt_get_errno
  194. // 下列表示没问题,但需要退出发送
  195. if (EAGAIN == rt_errno || // 套接字已标记为非阻塞,而接收操作被阻塞或者接收超时
  196. EWOULDBLOCK == rt_errno || // 发送时套接字发送缓冲区已满,或接收时套接字接收缓冲区为空
  197. EINTR == rt_errno || // 操作被信号中断
  198. ETIME == rt_errno) // 计时器过期
  199. {
  200. return 0;
  201. }
  202. // NOLINTNEXTLINE(concurrency-mt-unsafe)
  203. rlog_e("sendResult: %d, errno: %d str: %s", sendResult, rt_errno, strerror(rt_errno));
  204. return -1;
  205. }
  206. return (int32_t)sendResult;
  207. }
  208. /**
  209. * @brief 断开mqtt服务器连接
  210. *
  211. * @param userData
  212. * @param platformNetwork
  213. * @return RyanMqttError_e
  214. */
  215. RyanMqttError_e platformNetworkClose(void *userData, platformNetwork_t *platformNetwork)
  216. {
  217. if (platformNetwork->socket >= 0)
  218. {
  219. close(platformNetwork->socket);
  220. rlog_w("platformNetworkClose socket close %d", platformNetwork->socket);
  221. platformNetwork->socket = -1;
  222. }
  223. return RyanMqttSuccessError;
  224. }