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