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 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 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 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