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