tcpserver.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. */
  9. #include <rtthread.h>
  10. #include <string.h>
  11. #if !defined(SAL_USING_POSIX)
  12. #error "Please enable SAL_USING_POSIX!"
  13. #else
  14. #include <sys/time.h>
  15. #include <sys/select.h>
  16. #endif
  17. #include <sys/socket.h> /* 使用BSD socket,需要包含socket.h头文件 */
  18. #include "netdb.h"
  19. #define DEBUG_TCP_SERVER
  20. #define DBG_TAG "TCP"
  21. #ifdef DEBUG_TCP_SERVER
  22. #define DBG_LVL DBG_LOG
  23. #else
  24. #define DBG_LVL DBG_INFO /* DBG_ERROR */
  25. #endif
  26. #include <rtdbg.h>
  27. #define BUFSZ (1024)
  28. static int started = 0;
  29. static int is_running = 0;
  30. static int port = 5000;
  31. static const char send_data[] = "This is TCP Server from RT-Thread."; /* 发送用到的数据 */
  32. static void tcpserv(void *arg)
  33. {
  34. int ret;
  35. char *recv_data; /* 用于接收的指针,后面会做一次动态分配以请求可用内存 */
  36. int sock, connected, bytes_received;
  37. struct sockaddr_in server_addr, client_addr;
  38. struct timeval timeout;
  39. fd_set readset, readset_c;
  40. socklen_t sin_size = sizeof(struct sockaddr_in);
  41. recv_data = rt_malloc(BUFSZ + 1); /* 分配接收用的数据缓冲 */
  42. if (recv_data == RT_NULL)
  43. {
  44. LOG_E("No memory");
  45. return;
  46. }
  47. /* 一个socket在使用前,需要预先创建出来,指定SOCK_STREAM为TCP的socket */
  48. if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
  49. {
  50. LOG_E("Create socket error");
  51. goto __exit;
  52. }
  53. /* 初始化服务端地址 */
  54. server_addr.sin_family = AF_INET;
  55. server_addr.sin_port = htons(port); /* 服务端工作的端口 */
  56. server_addr.sin_addr.s_addr = INADDR_ANY;
  57. rt_memset(&(server_addr.sin_zero), 0x0, sizeof(server_addr.sin_zero));
  58. /* 绑定socket到服务端地址 */
  59. if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
  60. {
  61. LOG_E("Unable to bind");
  62. goto __exit;
  63. }
  64. /* 在socket上进行监听 */
  65. if (listen(sock, 10) == -1)
  66. {
  67. LOG_E("Listen error");
  68. goto __exit;
  69. }
  70. LOG_I("\nTCPServer Waiting for client on port %d...\n", port);
  71. started = 1;
  72. is_running = 1;
  73. timeout.tv_sec = 3;
  74. timeout.tv_usec = 0;
  75. while (is_running)
  76. {
  77. FD_ZERO(&readset);
  78. FD_SET(sock, &readset);
  79. LOG_I("Waiting for a new connection...");
  80. /* Wait for read or write */
  81. if (select(sock + 1, &readset, RT_NULL, RT_NULL, &timeout) == 0)
  82. continue;
  83. /* 接受一个客户端连接socket的请求,这个函数调用是阻塞式的 */
  84. connected = accept(sock, (struct sockaddr *)&client_addr, &sin_size);
  85. /* 返回的是连接成功的socket */
  86. if (connected < 0)
  87. {
  88. LOG_E("accept connection failed! errno = %d", errno);
  89. continue;
  90. }
  91. /* 接受返回的client_addr指向了客户端的地址信息 */
  92. LOG_I("I got a connection from (%s , %d)\n",
  93. inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
  94. /* 客户端连接的处理 */
  95. while (is_running)
  96. {
  97. FD_ZERO(&readset_c);
  98. FD_SET(connected, &readset_c);
  99. /* Wait for read or write */
  100. if (select(connected + 1, &readset_c, RT_NULL, RT_NULL, &timeout) == 0)
  101. continue;
  102. /* 从connected socket中接收数据,接收buffer是1024大小,但并不一定能够收到1024大小的数据 */
  103. bytes_received = recv(connected, recv_data, BUFSZ, 0);
  104. if (bytes_received < 0)
  105. {
  106. LOG_E("Received error, close the connect.");
  107. closesocket(connected);
  108. connected = -1;
  109. break;
  110. }
  111. else if (bytes_received == 0)
  112. {
  113. /* 打印recv函数返回值为0的警告信息 */
  114. LOG_W("Received warning, recv function return 0.");
  115. continue;
  116. }
  117. else
  118. {
  119. /* 有接收到数据,把末端清零 */
  120. recv_data[bytes_received] = '\0';
  121. if (strcmp(recv_data, "q") == 0 || strcmp(recv_data, "Q") == 0)
  122. {
  123. /* 如果是首字母是q或Q,关闭这个连接 */
  124. LOG_I("Got a 'q' or 'Q', close the connect.");
  125. closesocket(connected);
  126. connected = -1;
  127. break;
  128. }
  129. else if (strcmp(recv_data, "exit") == 0)
  130. {
  131. /* 如果接收的是exit,则关闭整个服务端 */
  132. closesocket(connected);
  133. connected = -1;
  134. goto __exit;
  135. }
  136. else
  137. {
  138. /* 在控制终端显示收到的数据 */
  139. LOG_D("Received data = %s", recv_data);
  140. }
  141. }
  142. /* 发送数据到connected socket */
  143. ret = send(connected, send_data, rt_strlen(send_data), 0);
  144. if (ret < 0)
  145. {
  146. LOG_E("send error, close the connect.");
  147. closesocket(connected);
  148. connected = -1;
  149. break;
  150. }
  151. else if (ret == 0)
  152. {
  153. /* 打印send函数返回值为0的警告信息 */
  154. LOG_W("Send warning, send function return 0.");
  155. }
  156. }
  157. }
  158. __exit:
  159. if (recv_data)
  160. {
  161. rt_free(recv_data);
  162. recv_data = RT_NULL;
  163. }
  164. if (connected >= 0)
  165. {
  166. closesocket(connected);
  167. connected = -1;
  168. }
  169. if (sock >= 0)
  170. {
  171. closesocket(sock);
  172. sock = -1;
  173. }
  174. started = 0;
  175. is_running = 0;
  176. return;
  177. }
  178. static void usage(void)
  179. {
  180. rt_kprintf("Usage: tcpserver -p <port>\n");
  181. rt_kprintf(" tcpserver --stop\n");
  182. rt_kprintf(" tcpserver --help\n");
  183. rt_kprintf("\n");
  184. rt_kprintf("Miscellaneous:\n");
  185. rt_kprintf(" -p Specify the host port number\n");
  186. rt_kprintf(" --stop Stop tcpserver program\n");
  187. rt_kprintf(" --help Print help information\n");
  188. }
  189. static void tcpserver_test(int argc, char** argv)
  190. {
  191. rt_thread_t tid;
  192. if (argc == 1 || argc > 3)
  193. {
  194. LOG_I("Please check the command you entered!\n");
  195. goto __usage;
  196. }
  197. else
  198. {
  199. if (rt_strcmp(argv[1], "--help") == 0)
  200. {
  201. goto __usage;
  202. }
  203. else if (rt_strcmp(argv[1], "--stop") == 0)
  204. {
  205. is_running = 0;
  206. return;
  207. }
  208. else if (rt_strcmp(argv[1], "-p") == 0)
  209. {
  210. if (started)
  211. {
  212. LOG_I("The tcpserver has started!");
  213. LOG_I("Please stop tcpserver firstly, by: tcpserver --stop");
  214. return;
  215. }
  216. port = atoi(argv[2]);
  217. }
  218. else
  219. {
  220. goto __usage;
  221. }
  222. }
  223. tid = rt_thread_create("tcp_serv",
  224. tcpserv, RT_NULL,
  225. 2048, RT_THREAD_PRIORITY_MAX/3, 20);
  226. if (tid != RT_NULL)
  227. {
  228. rt_thread_startup(tid);
  229. }
  230. return;
  231. __usage:
  232. usage();
  233. }
  234. #ifdef RT_USING_FINSH
  235. MSH_CMD_EXPORT_ALIAS(tcpserver_test, tcpserver,
  236. Start a tcp server. Help: tcpserver --help);
  237. #endif