udpserver.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-01-24 ChungHsuan improve code comments
  9. */
  10. #include <rtthread.h>
  11. #include <string.h>
  12. #if !defined(SAL_USING_POSIX)
  13. #error "Please enable SAL_USING_POSIX!"
  14. #else
  15. #include <sys/time.h>
  16. #include <sys/select.h>
  17. #endif
  18. #include <sys/socket.h> /* socket.h header file is needed when using BSD socket */ /* 使用BSD socket,需要包含socket.h头文件 */
  19. #include "netdb.h"
  20. #define DEBUG_UDP_SERVER
  21. #define DBG_TAG "UDP"
  22. #ifdef DEBUG_UDP_SERVER
  23. #define DBG_LVL DBG_LOG
  24. #else
  25. #define DBG_LVL DBG_INFO /* DBG_ERROR */
  26. #endif
  27. #include <rtdbg.h>
  28. #define BUFSZ 1024
  29. static int started = 0;
  30. static int is_running = 0;
  31. static int port = 5000;
  32. /**
  33. * @brief This function is for creating a udp server on RT-Thread
  34. */
  35. static void udpserv(void *paramemter)
  36. {
  37. int sock;
  38. int bytes_read;
  39. char *recv_data;
  40. socklen_t addr_len;
  41. struct sockaddr_in server_addr, client_addr;
  42. struct timeval timeout;
  43. fd_set readset;
  44. /* Allocate space for recv_data */
  45. /* 分配接收用的数据缓冲 */
  46. recv_data = rt_malloc(BUFSZ);
  47. if (recv_data == RT_NULL)
  48. {
  49. LOG_E("No memory");
  50. return;
  51. }
  52. /* Create a socket and set it to SOCK_DGRAM(UDP) */
  53. /* 创建一个socket,类型是SOCK_DGRAM,UDP类型 */
  54. if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
  55. {
  56. LOG_E("Create socket error");
  57. goto __exit;
  58. }
  59. /* Initialize server side address */
  60. /* 初始化服务端地址 */
  61. server_addr.sin_family = AF_INET;
  62. server_addr.sin_port = htons(port);
  63. server_addr.sin_addr.s_addr = INADDR_ANY;
  64. rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
  65. /* Bind socket to server side address */
  66. /* 绑定socket到服务端地址 */
  67. if (bind(sock, (struct sockaddr *)&server_addr,
  68. sizeof(struct sockaddr)) == -1)
  69. {
  70. LOG_E("Unable to bind");
  71. goto __exit;
  72. }
  73. addr_len = sizeof(struct sockaddr);
  74. LOG_I("UDPServer Waiting for client on port %d...", port);
  75. started = 1;
  76. is_running = 1;
  77. timeout.tv_sec = 3;
  78. timeout.tv_usec = 0;
  79. while (is_running)
  80. {
  81. FD_ZERO(&readset);
  82. FD_SET(sock, &readset);
  83. /* Wait for read or write */
  84. if (select(sock + 1, &readset, RT_NULL, RT_NULL, &timeout) == 0)
  85. continue;
  86. /* The maximum size received from sock is BUFSZ-1 bytes*/
  87. /* 从sock中收取最大BUFSZ - 1字节数据 */
  88. bytes_read = recvfrom(sock, recv_data, BUFSZ - 1, 0,
  89. (struct sockaddr *)&client_addr, &addr_len);
  90. if (bytes_read < 0)
  91. {
  92. LOG_E("Received error, close the connect.");
  93. goto __exit;
  94. }
  95. else if (bytes_read == 0)
  96. {
  97. LOG_W("Received warning, recv function returns 0.");
  98. continue;
  99. }
  100. else
  101. {
  102. recv_data[bytes_read] = '\0'; /* Append '\0' at the end of message *//* 把末端清零 */
  103. /* Output received message */
  104. /* 输出接收的数据 */
  105. LOG_D("Received data = %s", recv_data);
  106. /* If the message received is 'exit', quit. */
  107. /* 如果接收数据是exit,退出 */
  108. if (strcmp(recv_data, "exit") == 0)
  109. {
  110. goto __exit;
  111. }
  112. }
  113. }
  114. __exit:
  115. if (recv_data)
  116. {
  117. rt_free(recv_data);
  118. recv_data = RT_NULL;
  119. }
  120. if (sock >= 0)
  121. {
  122. closesocket(sock);
  123. sock = -1;
  124. }
  125. started = 0;
  126. is_running = 0;
  127. }
  128. /**
  129. * @brief The usage description of udp server on rt-Thread
  130. */
  131. static void usage(void)
  132. {
  133. rt_kprintf("Usage: udpserver -p <port>\n");
  134. rt_kprintf(" udpserver --stop\n");
  135. rt_kprintf(" udpserver --help\n");
  136. rt_kprintf("\n");
  137. rt_kprintf("Miscellaneous:\n");
  138. rt_kprintf(" -p Specify the host port number\n");
  139. rt_kprintf(" --stop Stop udpserver program\n");
  140. rt_kprintf(" --help Print help information\n");
  141. }
  142. /**
  143. * @brief This function is for testing udp server on rt-Thread
  144. */
  145. static void udpserver_test(int argc, char** argv)
  146. {
  147. rt_thread_t tid;
  148. if (argc == 1 || argc > 3)
  149. {
  150. LOG_I("Please check the command you entered!\n");
  151. goto __usage;
  152. }
  153. else
  154. {
  155. if (rt_strcmp(argv[1], "--help") == 0)
  156. {
  157. goto __usage;
  158. }
  159. else if (rt_strcmp(argv[1], "--stop") == 0)
  160. {
  161. is_running = 0;
  162. return;
  163. }
  164. else if (rt_strcmp(argv[1], "-p") == 0)
  165. {
  166. if (started)
  167. {
  168. LOG_I("The udpserver has started!");
  169. LOG_I("Please stop udpserver firstly, by: udpserver --stop");
  170. return;
  171. }
  172. port = atoi(argv[2]);
  173. }
  174. else
  175. {
  176. goto __usage;
  177. }
  178. }
  179. tid = rt_thread_create("udp_serv",
  180. udpserv, RT_NULL,
  181. 2048, RT_THREAD_PRIORITY_MAX/3, 20);
  182. if (tid != RT_NULL)
  183. {
  184. rt_thread_startup(tid);
  185. }
  186. return;
  187. __usage:
  188. usage();
  189. }
  190. #ifdef RT_USING_FINSH
  191. MSH_CMD_EXPORT_ALIAS(udpserver_test, udpserver,
  192. Start a udp server. Help: udpserver --help);
  193. #endif