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