当前位置:   article > 正文

智能家居2 -- 实现网络控制模块

智能家居2 -- 实现网络控制模块

这一模块的思路和前面的语言控制模块很相似,差别只是调用TCP 去控制

废话少说,放码过来

增添/修改代码

socket_interface.c

  1. #include <pthread.h>
  2. #include "socket_interface.h"
  3. #include "control.h"
  4. #include "socket.h"
  5. #include "mq_queue.h"
  6. #include "global.h"
  7. #include <netinet/tcp.h> // 设置 tcp 心跳 的参数
  8. static int s_fd = -1;
  9. static int tcpsocket_init(void)
  10. {
  11. s_fd = socket_init(IPADDR,IPPORT);
  12. //return s_fd;
  13. return -1;
  14. }
  15. static void tcpsocket_final(void)
  16. {
  17. close(s_fd);
  18. s_fd = -1;
  19. }
  20. static void* tcpsocket_get(void *arg)
  21. {
  22. int c_fd = -1;
  23. unsigned char buffer[BUF_SIZE];
  24. int ret = -1;
  25. struct sockaddr_in c_addr;
  26. mqd_t mqd = -1;
  27. ctrl_info_t * ctrl_info = NULL;
  28. int keepalive = 1; // 开启TCP_KEEPALIVE选项
  29. int keepidle = 10; // 设置探测时间间隔为10秒
  30. int keepinterval = 5; // 设置探测包发送间隔为5秒
  31. int keepcount = 3; // 设置探测包发送次数为3次
  32. pthread_detach(pthread_self()); // 和主线程(他的父线程)分离
  33. printf("%s|%s|%d s_fd = %d\n", __FILE__, __func__, __LINE__, s_fd);
  34. if(-1 == s_fd) // 判断是否初始化成功
  35. {
  36. s_fd = tcpsocket_init();
  37. if(-1 == s_fd)
  38. {
  39. printf("tcpsocket_init error\n");
  40. pthread_exit(0);
  41. }
  42. }
  43. if(NULL != arg)
  44. ctrl_info = (ctrl_info_t*)arg;
  45. if(NULL != ctrl_info)
  46. mqd = ctrl_info->mqd;
  47. if((mqd_t)-1 == mqd)
  48. {
  49. pthread_exit(0);
  50. }
  51. memset(&c_addr, 0, sizeof(struct sockaddr_in));
  52. int clen = sizeof(struct sockaddr_in);
  53. printf("%s thread start\n", __func__);
  54. while (1) // 一直等待接收
  55. {
  56. c_fd = accept(s_fd, (struct sockaddr *)&c_addr, &clen); // 获得新的客户端 描述符
  57. if (c_fd == -1)
  58. {
  59. continue;
  60. }
  61. ret = setsockopt(c_fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive,sizeof(keepalive));
  62. if(-1 == ret){
  63. perror("setsockopt");
  64. break;
  65. }
  66. ret = setsockopt(c_fd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&keepidle, sizeof(keepidle));
  67. if(-1 == ret){
  68. perror("setsockopt");
  69. break;
  70. }
  71. ret = setsockopt(c_fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepinterval,
  72. sizeof(keepinterval));
  73. if(-1 == ret){
  74. perror("setsockopt");
  75. break;
  76. }
  77. ret = setsockopt(c_fd, IPPROTO_TCP, TCP_KEEPCNT, &keepcount,
  78. sizeof(keepcount));
  79. if(-1 == ret){
  80. perror("setsockopt");
  81. break;
  82. }
  83. // 打印调试信息
  84. printf("%s | %s | %d: Access a connection from %s:%d\n", __FILE__, __func__, __LINE__, inet_ntoa(c_addr.sin_addr), ntohs(c_addr.sin_port));
  85. while (1)
  86. {
  87. memset(buffer, 0, BUF_SIZE);
  88. ret = recv(c_fd, buffer, BUF_SIZE, 0); // 等待接收
  89. // 将接收到数据打印出来
  90. printf("%s|%s|%d, 0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\n",__FILE__,__func__,__LINE__,buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5]);
  91. if (ret > 0)
  92. {
  93. if(buffer[0] == 0xAA && buffer[1] == 0x55
  94. &&buffer[4]==0x55 && buffer[5]==0xAA)
  95. {
  96. printf("%s|%s|%d, send: 0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\n",__FILE__,__func__,__LINE__,buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5]);
  97. send_msg(mqd,buffer,ret);
  98. }
  99. }
  100. else if (0 == ret || -1 == ret) // 没读到,or 读到空
  101. {
  102. break;
  103. }
  104. }
  105. }
  106. pthread_exit(0);
  107. }
  108. struct control tcpsocket_control ={
  109. .control_name = "tcpsocket",
  110. .init = tcpsocket_init,
  111. .final = tcpsocket_final,
  112. .get = tcpsocket_get,
  113. .set = NULL, //不需要实现 设置
  114. .next = NULL
  115. };
  116. struct control *add_tcpsocket_to_ctrl_list(struct control *phead)
  117. {
  118. //头插法实现 添加链表节点
  119. struct control *pnew = NULL;
  120. if(NULL == phead)
  121. {
  122. phead = &tcpsocket_control; // 直接传入我们的 voice_control
  123. }
  124. else// 头结点非空 - 链表有数据
  125. {
  126. tcpsocket_control.next = phead; //把新的节点的next指向头结点
  127. phead = &tcpsocket_control; // 让心节点成为头结点
  128. }
  129. return phead;
  130. };



socket_interface.h

  1. #ifndef ___SOCKET_INTERFACE_H___
  2. #define ___SOCKET_INTERFACE_H___
  3. #include "control.h"
  4. struct control *add_tcpsocket_to_ctrl_list(struct control *phead);
  5. #endif

修改的main.c

  1. #include <stdio.h>
  2. #include <pthread.h>
  3. #include <stdlib.h>
  4. #include "control.h"
  5. #include "mq_queue.h"
  6. #include "voice_interface.h"
  7. #include "socket_interface.h"
  8. #include "global.h"
  9. // msg_queue_create
  10. int main() {
  11. pthread_t thread_id;
  12. struct control *control_phead = NULL;
  13. struct control *pointer = NULL;
  14. ctrl_info_t *ctrl_info = NULL;
  15. ctrl_info = (ctrl_info_t *)malloc(sizeof(ctrl_info_t));
  16. ctrl_info->ctrl_phead = NULL;
  17. ctrl_info->mqd = -1;
  18. int node_num = 0; // 统计节点数
  19. // 创建消息队列
  20. ctrl_info->mqd = msg_queue_create();
  21. if(-1 == ctrl_info->mqd)// 创建消息队列失败
  22. {
  23. printf("%s|%s|%d, mqd= %d\n",__FILE__,__func__,__LINE__,ctrl_info->mqd);
  24. return -1;
  25. }
  26. ctrl_info->ctrl_phead = add_voice_to_ctrl_list(ctrl_info->ctrl_phead);
  27. ctrl_info->ctrl_phead = add_tcpsocket_to_ctrl_list(ctrl_info->ctrl_phead);
  28. //ctrl_info->ctrl_phead = add_fire_to_ctrl_list(ctrl_info->ctrl_phead);
  29. pointer = ctrl_info->ctrl_phead;
  30. while(NULL!=pointer) // 对所有控制结构体初始化,并且统计节点数
  31. {
  32. if(NULL != pointer->init)
  33. {
  34. printf("%s|%s|%d control_name = %s\n",__FILE__,__func__,__LINE__,pointer->control_name);
  35. pointer->init();
  36. }
  37. pointer = pointer->next;
  38. node_num++; // 统计节点数
  39. }
  40. // 根据节点的总数 --> 创建对应数目的线程
  41. pthread_t *tid = (pthread_t *)malloc(sizeof(int) *node_num);
  42. pointer = ctrl_info->ctrl_phead;
  43. for(int i=0;i<node_num;++i)//遍历所有节点
  44. {
  45. if(NULL != pointer->get){
  46. printf("%s|%s|%d control_name = %s\n",__FILE__,__func__,__LINE__,pointer->control_name);
  47. pthread_create(&tid[i],NULL,(void *)pointer->get,(void *)ctrl_info); // 传入这个结构体参数,方便同时调用多组线程里面的API
  48. }
  49. pointer = pointer->next;
  50. }
  51. for(int i=0;i<node_num;++i)
  52. {
  53. pthread_join(tid[i],NULL);
  54. }
  55. for(int i=0;i<node_num;++i)
  56. {
  57. if(NULL != pointer->final)
  58. pointer->final(); // 接打开的使用接口关闭
  59. pointer = pointer->next;
  60. }
  61. msq_queue_final(ctrl_info->mqd);
  62. }

编译执行:

编译:

make

发送到arm-64平台

scp ./obj/smarthome  orangepi@192.168.1.11:/home/orangepi

执行:

sudo -E ./smarthome

/遇到如下报错 -- 解决:


scp: /home/orangepi/smarthome: Text file busy

kill -9 进程即可

 kill之后成功了

bind: Address already in use
 

要解决这个问题,您可以尝试以下步骤:

  1. 查找并关闭现有进程:使用 netstatlsof 或 ss 命令来查找正在监听该端口的进程,并关闭它。

     
    1. sudo netstat -tulnp | grep [端口号]
    2. # 或者
    3. sudo lsof -i :[端口号]
    4. # 或者
    5. sudo ss -tulnp | grep [端口号]
     

    找到进程ID(PID)后,使用 kill -9 命令来结束该进程。

  2. 重启计算机:如果无法确定哪个进程正在使用端口,或者无法结束该进程,您可以考虑重启计算机

  3. 使用不同的端口:如果您只是想要快速测试您的应用程序,并且不关心特定的端口号,您可以尝试使用另一个端口。

TCP验证:

(注意发送格式 16进制)

否则你发送的数据很可能变成这样

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/567365
推荐阅读
相关标签
  

闽ICP备14008679号