فهرست منبع

[examples][network] 更新 tcp client & server 例程

Signed-off-by: MurphyZhao <d2014zjt@163.com>
MurphyZhao 6 سال پیش
والد
کامیت
6c62f5d9fe
2فایلهای تغییر یافته به همراه344 افزوده شده و 121 حذف شده
  1. 161 50
      examples/network/tcpclient.c
  2. 183 71
      examples/network/tcpserver.c

+ 161 - 50
examples/network/tcpclient.c

@@ -1,27 +1,60 @@
 #include <rtthread.h>
+#include <string.h>
 
+#if !defined(SAL_USING_POSIX)
+#error "Please enable SAL_USING_POSIX!"
+#else
+#include <sys/time.h>
+#include <sys/select.h>
+#endif
 #include <sys/socket.h> /* 使用BSD socket,需要包含socket.h头文件 */
 #include "netdb.h"
 
+#define DEBUG_TCP_CLIENT
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME               "TCP"
+#ifdef DEBUG_TCP_CLIENT
+#define DBG_LEVEL                      DBG_LOG
+#else
+#define DBG_LEVEL                      DBG_INFO /* DBG_ERROR */
+#endif
+#define DBG_COLOR
+#include <rtdbg.h>
+
 #define BUFSZ   1024
 
+static int started = 0;
+static int is_running = 0;
+static char url[256];
+static int port = 8080;
 static const char send_data[] = "This is TCP Client from RT-Thread."; /* 发送用到的数据 */
-void tcpclient(const char *url, int port)
+
+static void tcpclient(void *arg)
 {
     int ret;
     char *recv_data;
-    struct hostent *host;
-    int sock, bytes_received;
+    int bytes_received;
+    int sock = -1;
+    struct hostent *host = RT_NULL;
     struct sockaddr_in server_addr;
 
+    struct timeval timeout;
+    fd_set readset;
+
     /* 通过函数入口参数url获得host地址(如果是域名,会做域名解析) */
     host = gethostbyname(url);
+    if (host == RT_NULL)
+    {
+        LOG_E("Get host by name failed!");
+        return;
+    }
 
     /* 分配用于存放接收数据的缓冲 */
     recv_data = rt_malloc(BUFSZ);
     if (recv_data == RT_NULL)
     {
-        rt_kprintf("No memory\n");
+        LOG_E("No memory");
         return;
     }
 
@@ -29,11 +62,8 @@ void tcpclient(const char *url, int port)
     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
     {
         /* 创建socket失败 */
-        rt_kprintf("Socket error\n");
-
-        /* 释放接收缓冲 */
-        rt_free(recv_data);
-        return;
+        LOG_E("Create socket error");
+        goto __exit;
     }
 
     /* 初始化预连接的服务端地址 */
@@ -46,78 +76,159 @@ void tcpclient(const char *url, int port)
     if (connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
     {
         /* 连接失败 */
-        rt_kprintf("Connect fail!\n");
-        closesocket(sock);
-
-        /*释放接收缓冲 */
-        rt_free(recv_data);
-        return;
+        LOG_E("Connect fail!");
+        goto __exit;
     }
 
-    while (1)
+    started = 1;
+    is_running = 1;
+
+    timeout.tv_sec = 3;
+    timeout.tv_usec = 0;
+
+    while (is_running)
     {
+        FD_ZERO(&readset);
+        FD_SET(sock, &readset);
+
+        /* Wait for read */
+        if (select(sock + 1, &readset, RT_NULL, RT_NULL, &timeout) == 0)
+            continue;
+
         /* 从sock连接中接收最大BUFSZ - 1字节数据 */
         bytes_received = recv(sock, recv_data, BUFSZ - 1, 0);
         if (bytes_received < 0)
         {
             /* 接收失败,关闭这个连接 */
-            closesocket(sock);
-            rt_kprintf("\nreceived error,close the socket.\r\n");
-
-            /* 释放接收缓冲 */
-            rt_free(recv_data);
-            break;
+            LOG_E("Received error, close the socket.");
+            goto __exit;
         }
         else if (bytes_received == 0)
         {
             /* 打印recv函数返回值为0的警告信息 */
-            rt_kprintf("\nReceived warning,recv function return 0.\r\n");
-
+            LOG_W("Received warning, recv function return 0.");
             continue;
         }
-
-        /* 有接收到数据,把末端清零 */
-        recv_data[bytes_received] = '\0';
-
-        if (strcmp(recv_data, "q") == 0 || strcmp(recv_data, "Q") == 0)
-        {
-            /* 如果是首字母是q或Q,关闭这个连接 */
-            closesocket(sock);
-            rt_kprintf("\n got a 'q' or 'Q',close the socket.\r\n");
-
-            /* 释放接收缓冲 */
-            rt_free(recv_data);
-            break;
-        }
         else
         {
-            /* 在控制终端显示收到的数据 */
-            rt_kprintf("\nReceived data = %s ", recv_data);
+            /* 有接收到数据,把末端清零 */
+            recv_data[bytes_received] = '\0';
+
+            if (rt_strcmp(recv_data, "q") == 0 || rt_strcmp(recv_data, "Q") == 0)
+            {
+                /* 如果是首字母是q或Q,关闭这个连接 */
+                LOG_I("Got a 'q' or 'Q', close the socket.");
+                goto __exit;
+            }
+            else
+            {
+                /* 在控制终端显示收到的数据 */
+                LOG_D("Received data = %s", recv_data);
+            }
         }
 
         /* 发送数据到sock连接 */
-        ret = send(sock, send_data, strlen(send_data), 0);
+        ret = send(sock, send_data, rt_strlen(send_data), 0);
         if (ret < 0)
         {
             /* 接收失败,关闭这个连接 */
-            closesocket(sock);
-            rt_kprintf("\nsend error,close the socket.\r\n");
-
-            rt_free(recv_data);
-            break;
+            LOG_I("send error, close the socket.");
+            goto __exit;
         }
         else if (ret == 0)
         {
             /* 打印send函数返回值为0的警告信息 */
-            rt_kprintf("\n Send warning,send function return 0.\r\n");
+            LOG_W("Send warning, send function return 0.");
+        }
+    }
+
+__exit:
+    if (recv_data)
+    {
+        rt_free(recv_data);
+        recv_data = RT_NULL;
+    }
+    if (sock >= 0)
+    {
+        closesocket(sock);
+        sock = -1;
+    }
+    started = 0;
+    is_running = 0;
+    return;
+}
+
+static void usage(void)
+{
+    LOG_I("Usage: tcpclient -h <host> -p <port>");
+    LOG_I("       tcpclient --stop");
+    LOG_I("       tcpclient --help");
+    LOG_I("");
+    LOG_I("Miscellaneous:");
+    LOG_I("  -h           Specify host address");
+    LOG_I("  -p           Specify the host port number");
+    LOG_I("  --stop       Stop tcpclient program");
+    LOG_I("  --help       Print help information");
+}
+
+static void tcpclient_test(int argc, char** argv)
+{
+    rt_thread_t tid;
+
+    if (argc == 1 || argc > 5)
+    {
+        LOG_I("Please check the command you entered!\n");
+        goto __usage;
+    }
+    else
+    {
+        if (rt_strcmp(argv[1], "--help") == 0)
+        {
+            goto __usage;
+        }
+        else if (rt_strcmp(argv[1], "--stop") == 0)
+        {
+            is_running = 0;
+            return;
+        }
+        else if (rt_strcmp(argv[1], "-h") == 0 && rt_strcmp(argv[3], "-p") == 0)
+        {
+            if (started)
+            {
+                LOG_I("The tcpclient has started!");
+                LOG_I("Please stop tcpclient firstly, by: tcpclient --stop");
+                return;
+            }
+
+            if (rt_strlen(argv[2]) > sizeof(url))
+            {
+                LOG_E("The input url is too long, max %d bytes!", sizeof(url));
+                return;
+            }
+            rt_memset(url, 0x0, sizeof(url));
+            rt_strncpy(url, argv[2], rt_strlen(argv[2]));
+            port = atoi(argv[4]);
+        }
+        else
+        {
+            goto __usage;
         }
     }
 
+    tid = rt_thread_create("tcp_client",
+        tcpclient, RT_NULL,
+        2048, RT_THREAD_PRIORITY_MAX/3, 20);
+    if (tid != RT_NULL)
+    {
+        rt_thread_startup(tid);
+    }
     return;
+
+__usage:
+    usage();
 }
 
 #ifdef RT_USING_FINSH
-#include <finsh.h>
-/* 输出tcpclient函数到finsh shell中 */
-FINSH_FUNCTION_EXPORT(tcpclient, startup tcp client);
+MSH_CMD_EXPORT_ALIAS(tcpclient_test, tcpclient,
+    Start a tcp client. Help: tcpclient --help);
 #endif

+ 183 - 71
examples/network/tcpserver.c

@@ -1,151 +1,263 @@
 #include <rtthread.h>
+#include <string.h>
 
+#if !defined(SAL_USING_POSIX)
+#error "Please enable SAL_USING_POSIX!"
+#else
+#include <sys/time.h>
+#include <sys/select.h>
+#endif
 #include <sys/socket.h> /* 使用BSD socket,需要包含socket.h头文件 */
 #include "netdb.h"
 
+#define DEBUG_TCP_SERVER
+
+#define DBG_ENABLE
+#define DBG_SECTION_NAME               "TCP"
+#ifdef DEBUG_TCP_SERVER
+#define DBG_LEVEL                      DBG_LOG
+#else
+#define DBG_LEVEL                      DBG_INFO /* DBG_ERROR */
+#endif
+#define DBG_COLOR
+#include <rtdbg.h>
+
 #define BUFSZ       (1024)
 
+static int started = 0;
+static int is_running = 0;
+static int port = 5000;
 static const char send_data[] = "This is TCP Server from RT-Thread."; /* 发送用到的数据 */
-static void tcpserv(void *parameter)
+
+static void tcpserv(void *arg)
 {
+    int ret;
     char *recv_data; /* 用于接收的指针,后面会做一次动态分配以请求可用内存 */
-    socklen_t sin_size;
     int sock, connected, bytes_received;
     struct sockaddr_in server_addr, client_addr;
-    rt_bool_t stop = RT_FALSE; /* 停止标志 */
-    int ret;
+
+    struct timeval timeout;
+    fd_set readset, readset_c;
+    socklen_t sin_size = sizeof(struct sockaddr_in);
 
     recv_data = rt_malloc(BUFSZ + 1); /* 分配接收用的数据缓冲 */
     if (recv_data == RT_NULL)
     {
-        rt_kprintf("No memory\n");
+        LOG_E("No memory");
         return;
     }
 
     /* 一个socket在使用前,需要预先创建出来,指定SOCK_STREAM为TCP的socket */
-    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+    if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
     {
-        /* 创建失败的错误处理 */
-        rt_kprintf("Socket error\n");
-
-        /* 释放已分配的接收缓冲 */
-        rt_free(recv_data);
-        return;
+        LOG_E("Create socket error");
+        goto __exit;
     }
 
     /* 初始化服务端地址 */
     server_addr.sin_family = AF_INET;
-    server_addr.sin_port = htons(5000); /* 服务端工作的端口 */
+    server_addr.sin_port = htons(port); /* 服务端工作的端口 */
     server_addr.sin_addr.s_addr = INADDR_ANY;
-    rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
+    rt_memset(&(server_addr.sin_zero), 0x0, sizeof(server_addr.sin_zero));
 
     /* 绑定socket到服务端地址 */
     if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
     {
-        /* 绑定失败 */
-        rt_kprintf("Unable to bind\n");
-
-        /* 释放已分配的接收缓冲 */
-        rt_free(recv_data);
-        return;
+        LOG_E("Unable to bind");
+        goto __exit;
     }
 
     /* 在socket上进行监听 */
-    if (listen(sock, 5) == -1)
+    if (listen(sock, 10) == -1)
     {
-        rt_kprintf("Listen error\n");
-
-        /* release recv buffer */
-        rt_free(recv_data);
-        return;
+        LOG_E("Listen error");
+        goto __exit;
     }
 
-    rt_kprintf("\nTCPServer Waiting for client on port 5000...\n");
-    while (stop != RT_TRUE)
+    LOG_I("\nTCPServer Waiting for client on port %d...\n", port);
+
+    started = 1;
+    is_running = 1;
+
+    timeout.tv_sec = 3;
+    timeout.tv_usec = 0;
+
+    while (is_running)
     {
-        sin_size = sizeof(struct sockaddr_in);
+        FD_ZERO(&readset);
+        FD_SET(sock, &readset);
+
+        LOG_I("Waiting for a new connection...");
+
+        /* Wait for read or write */
+        if (select(sock + 1, &readset, RT_NULL, RT_NULL, &timeout) == 0)
+            continue;
 
         /* 接受一个客户端连接socket的请求,这个函数调用是阻塞式的 */
         connected = accept(sock, (struct sockaddr *)&client_addr, &sin_size);
         /* 返回的是连接成功的socket */
         if (connected < 0)
         {
-            rt_kprintf("accept connection failed! errno = %d\n", errno);
+            LOG_E("accept connection failed! errno = %d", errno);
             continue;
         }
 
         /* 接受返回的client_addr指向了客户端的地址信息 */
-        rt_kprintf("I got a connection from (%s , %d)\n",
+        LOG_I("I got a connection from (%s , %d)\n",
                    inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
 
         /* 客户端连接的处理 */
-        while (1)
+        while (is_running)
         {
-            /* 发送数据到connected socket */
-            ret = send(connected, send_data, strlen(send_data), 0);
-            if (ret < 0)
-            {
-                /* 发送失败,关闭这个连接 */
-                closesocket(connected);
-                rt_kprintf("\nsend error,close the socket.\r\n");
-                break;
-            }
-            else if (ret == 0)
-            {
-                /* 打印send函数返回值为0的警告信息 */
-                rt_kprintf("\n Send warning,send function return 0.\r\n");
-            }
+            FD_ZERO(&readset_c);
+            FD_SET(connected, &readset_c);
+
+            /* Wait for read or write */
+            if (select(connected + 1, &readset_c, RT_NULL, RT_NULL, &timeout) == 0)
+                continue;
 
             /* 从connected socket中接收数据,接收buffer是1024大小,但并不一定能够收到1024大小的数据 */
             bytes_received = recv(connected, recv_data, BUFSZ, 0);
             if (bytes_received < 0)
             {
-                /* 接收失败,关闭这个connected socket */
+                LOG_E("Received error, close the connect.");
                 closesocket(connected);
+                connected = -1;
                 break;
             }
             else if (bytes_received == 0)
             {
                 /* 打印recv函数返回值为0的警告信息 */
-                rt_kprintf("\nReceived warning,recv function return 0.\r\n");
-                closesocket(connected);
-                break;
+                LOG_W("Received warning, recv function return 0.");
+                continue;
             }
-
-            /* 有接收到数据,把末端清零 */
-            recv_data[bytes_received] = '\0';
-            if (strcmp(recv_data, "q") == 0 || strcmp(recv_data, "Q") == 0)
+            else
             {
-                /* 如果是首字母是q或Q,关闭这个连接 */
-                closesocket(connected);
-                break;
+                /* 有接收到数据,把末端清零 */
+                recv_data[bytes_received] = '\0';
+                if (strcmp(recv_data, "q") == 0 || strcmp(recv_data, "Q") == 0)
+                {
+                    /* 如果是首字母是q或Q,关闭这个连接 */
+                    LOG_I("Got a 'q' or 'Q', close the connect.");
+                    closesocket(connected);
+                    connected = -1;
+                    break;
+                }
+                else if (strcmp(recv_data, "exit") == 0)
+                {
+                    /* 如果接收的是exit,则关闭整个服务端 */
+                    closesocket(connected);
+                    connected = -1;
+                    goto __exit;
+                }
+                else
+                {
+                    /* 在控制终端显示收到的数据 */
+                    LOG_D("Received data = %s", recv_data);
+                }
             }
-            else if (strcmp(recv_data, "exit") == 0)
+
+            /* 发送数据到connected socket */
+            ret = send(connected, send_data, rt_strlen(send_data), 0);
+            if (ret < 0)
             {
-                /* 如果接收的是exit,则关闭整个服务端 */
+                LOG_E("send error, close the connect.");
                 closesocket(connected);
-                stop = RT_TRUE;
+                connected = -1;
                 break;
             }
-            else
+            else if (ret == 0)
             {
-                /* 在控制终端显示收到的数据 */
-                rt_kprintf("RECEIVED DATA = %s \n", recv_data);
+                /* 打印send函数返回值为0的警告信息 */
+                LOG_W("Send warning, send function return 0.");
             }
         }
     }
 
-    /* 退出服务 */
-    closesocket(sock);
+__exit:
+    if (recv_data)
+    {
+        rt_free(recv_data);
+        recv_data = RT_NULL;
+    }
+    if (connected >= 0)
+    {
+        closesocket(connected);
+        connected = -1;
+    }
+    if (sock >= 0)
+    {
+        closesocket(sock);
+        sock = -1;
+    }
+    started = 0;
+    is_running = 0;
+    return;
+}
+
+static void usage(void)
+{
+    LOG_I("Usage: tcpserver -p <port>");
+    LOG_I("       tcpserver --stop");
+    LOG_I("       tcpserver --help");
+    LOG_I("");
+    LOG_I("Miscellaneous:");
+    LOG_I("  -p           Specify the host port number");
+    LOG_I("  --stop       Stop tcpserver program");
+    LOG_I("  --help       Print help information");
+}
+
+static void tcpserver_test(int argc, char** argv)
+{
+    rt_thread_t tid;
+
+    if (argc == 1 || argc > 3)
+    {
+        LOG_I("Please check the command you entered!\n");
+        goto __usage;
+    }
+    else
+    {
+        if (rt_strcmp(argv[1], "--help") == 0)
+        {
+            goto __usage;
+        }
+        else if (rt_strcmp(argv[1], "--stop") == 0)
+        {
+            is_running = 0;
+            return;
+        }
+        else if (rt_strcmp(argv[1], "-p") == 0)
+        {
+            if (started)
+            {
+                LOG_I("The tcpclient has started!");
+                LOG_I("Please stop tcpclient firstly, by: tcpclient --stop");
+                return;
+            }
+
+            port = atoi(argv[2]);
+        }
+        else
+        {
+            goto __usage;
+        }
+    }
 
-    /* 释放接收缓冲 */
-    rt_free(recv_data);
+    tid = rt_thread_create("tcp_serv",
+        tcpserv, RT_NULL,
+        2048, RT_THREAD_PRIORITY_MAX/3, 20);
+    if (tid != RT_NULL)
+    {
+        rt_thread_startup(tid);
+    }
+    return;
 
-    return ;
+__usage:
+    usage();
 }
 
 #ifdef RT_USING_FINSH
-#include <finsh.h>
-/* 输出tcpserv函数到finsh shell中 */
-FINSH_FUNCTION_EXPORT(tcpserv, startup tcp server);
+MSH_CMD_EXPORT_ALIAS(tcpserver_test, tcpserver,
+    Start a tcp server. Help: tcpserver --help);
 #endif