Ver código fonte

完善代码及文档

guozhanxin 6 anos atrás
pai
commit
90e33322e0
5 arquivos alterados com 338 adições e 41 exclusões
  1. 220 2
      README.md
  2. 4 1
      SConscript
  3. 33 23
      tcpserver.c
  4. 17 15
      tcpserver.h
  5. 64 0
      tcpserver_sample.c

+ 220 - 2
README.md

@@ -1,2 +1,220 @@
-# tcpserver
-A TCP server that supports multiple clients
+# TCP server
+## 简介
+
+本软件包是一个支持多客户端连接通讯的 TCP 服务器,使用简单的 API 就可以实现服务器的创建,并与不同的客户端通讯。
+
+本服务器有以下特点:
+
+- 多服务器同时运行
+- 多网卡支持,支持绑定到特定的 IP
+- 支持阻塞接收和非阻塞的通知回调接收。
+- 支持与不同的客户端独立的交换数据。
+
+## 使用说明
+
+### 依赖
+
+- RT-Thread 3.1.0+
+- SAL
+- DFS (select)
+
+### 获取软件包
+
+使用 tcpserver 软件包需要在 RT-Thread 的包管理中选中它,具体路径如下:
+
+```
+RT-Thread online packages --->
+    IoT - internet of things --->
+        [*] TCP Server:A TCP server that supports multiple clients
+            (tcpserv) tcpserver name
+            (4096) tcpserver stack size
+            (12)  tcpserver thread priority
+            (512) Maximum possible socket usage
+            (5)   Number of clients supported
+            [ ]   Enable debugging features
+            [*]   Enable sample
+                Version (latest)  --->
+```
+
+- **tcpserver name**: 配置 tcpserver 的名称
+- **tcpserver stack size**:配置线程栈的大小
+- **tcpserver thread priority**:配置线程的优先级
+- **Maximum possible socket usage**:系统可能用到的 socket 的最大值
+- **Number of clients supported**:支持同时连接的客户端数目
+- **Enable debugging features**:开启调试功能
+- **Enable sample**:开启示例代码
+- **Version**:软件包版本选择
+
+### 使用软件包
+
+#### API 详解
+
+##### 创建服务端
+
+创建一个 TCP 的服务端,传入服务端的 ip 地址和端口号。
+
+```
+struct tcpserver *tcpserver_create(const char *ip, rt_uint16_t port);
+```
+
+**函数参数**
+
+| 参数     | 描述                              |
+| -------- | --------------------------------- |
+| ip       | 要绑定的 ip 地址                  |
+| port     | 要绑定的 端口号                   |
+| **返回** | **——**                            |
+| >  0     | 成功,返回一个 tcp 服务端的句柄。 |
+| = 0      | 失败                              |
+
+##### 销毁服务端
+
+销毁一个 TCP 的服务端,并回收资源。
+
+```
+rt_err_t tcpserver_destroy(struct tcpserver *server);
+```
+
+**函数参数**
+
+| 参数     | 描述                      |
+| -------- | ------------------------- |
+| server   | 要销毁的 tcp 服务端的句柄 |
+| **返回** | **——**                    |
+| =  0     | 成功                      |
+| < 0      | 失败                      |
+
+##### 获取客户端
+
+获取一个 TCP 的客户端,阻塞式的获取一个客户端。
+
+```
+tcpclient_t tcpserver_accept(struct tcpserver *server, rt_int32_t timeout);
+```
+
+**函数参数**
+
+| 参数     | 描述                                              |
+| -------- | ------------------------------------------------- |
+| server   | tcp 服务端的句柄                                  |
+| timeout  | 等待的超时时间,RT_WAITING_FOREVER 表示永久等待。 |
+| **返回** | **——**                                            |
+| >  0     | 成功,返回一个 tcp 客户端的句柄。                 |
+| = 0      | 失败                                              |
+
+##### 关闭客户端
+
+关闭一个 TCP 的客户端。
+
+```
+rt_err_t tcpserver_close(tcpclient_t client);
+```
+
+**函数参数**
+
+| 参数     | 描述             |
+| -------- | ---------------- |
+| client   | tcp 客户端的句柄 |
+| **返回** | **——**           |
+| =  0     | 成功。           |
+| < 0      | 失败             |
+
+##### 从客户端接收数据
+
+从客户端接收数据。
+
+```
+rt_size_t tcpserver_recv(tcpclient_t client, void *buf, rt_size_t size, rt_int32_t timeout);
+```
+
+**函数参数**
+
+| 参数     | 描述                                              |
+| -------- | ------------------------------------------------- |
+| client   | tcp 客户端的句柄                                  |
+| buf      | 缓冲区地址                                        |
+| size     | 缓冲区大小                                        |
+| timeout  | 等待的超时时间,RT_WAITING_FOREVER 表示永久等待。 |
+| **返回** | **——**                                            |
+| >  0     | 成功,返回接收到的数据长度。                      |
+| = 0      | 失败                                              |
+
+##### 向客户端发送数据
+
+向客户端发送数据。
+
+```
+rt_size_t tcpserver_send(tcpclient_t client, void *buf, rt_size_t size, rt_int32_t timeout);
+```
+
+**函数参数**
+
+| 参数     | 描述                         |
+| -------- | ---------------------------- |
+| client   | tcp 客户端的句柄             |
+| buf      | 缓冲区地址                   |
+| size     | 缓冲区大小                   |
+| timeout  | 等待的超时时间,**暂未实现** |
+| **返回** | **——**                       |
+| >  0     | 成功,已发送的数据长度。     |
+| = 0      | 失败                         |
+
+##### 设定事件通知回调函数
+
+设定服务器的事件通知回调函数。
+
+```
+void tcpserver_set_notify_callback(struct tcpserver *server,
+                                   void (*tcpserver_event_notify)(tcpclient_t client, rt_uint8_t event));
+```
+
+**函数参数**
+
+| 参数                   | 描述             |
+| ---------------------- | ---------------- |
+| server                 | tcp 服务端的句柄 |
+| tcpserver_event_notify | 要设定的函数指针 |
+| **返回**               | **——**           |
+
+#### 运行示例程序
+
+软件包自带一个回显服务器的示例程序。开启软件包的示例程序之后,就可以使用。
+
+编译下载运行,会出现两个命令,`tcpserver`、`tcpserver_stop`。分别是创建 TCP server 和 关闭 TCP server。
+
+先输入 IP 地址和端口号 创建一个服务器,然后,就可以使用网络调试助手和此服务器通信了。输入`tcpserver_stop`关闭服务器。
+
+```
+ \ | /
+- RT -     Thread Operating System
+ / | \     3.1.3 build Jul 11 2019
+ 2006 - 2019 Copyright by rt-thread team
+lwIP-2.0.2 initialized!
+[4] I/sal.skt: Socket Abstraction Layer initialize success.
+msh />ifconfig
+network interface device: e0 (Default)
+MTU: 1500
+MAC: 00 04 a3 12 34 56
+FLAGS: UP LINK_UP INTERNET_UP DHCP_ENABLE ETHARP BROADCAST IGMP
+ip address: 192.168.12.117            # 本机 IP 地址
+gw address: 192.168.10.1
+net mask  : 255.255.0.0
+dns server #0: 192.168.10.1
+dns server #1: 223.5.5.5
+msh />tcpserver 192.168.12.117 5000   # 创建服务器
+msh />[173861] D/tcpserv: client connect:5  # 客户端连接成功
+[180220] D/tcpserv: client disconnect:5     # 客户端断开连接
+msh />tcpserver_stop                  # 关闭服务器
+msh />
+```
+
+## 注意事项
+
+- tcpserver_send 函数的超时机制还没有实现
+- 如果还没有到达设定的支持客户端的数目,但是总连接出错,可能是 lwip 的限制。
+
+## 联系人信息
+
+- 维护人: [flybreak](guozhanxin@rt-thread.com)
+
+- 主页:[tcpserver](<https://github.com/Guozhanxin/tcpserver>)

+ 4 - 1
SConscript

@@ -1,9 +1,12 @@
 from building import *
 
-src   = ['tcpserver']
+src     = ['tcpserver.c']
 cwd   = GetCurrentDir()
 include_path = [cwd]
 
+if GetDepend(['PKG_TCPSERVER_SAMPLE']):
+    src += ['tcpserver_sample.c']
+
 group = DefineGroup('tcpserver', src, depend = ['PKG_USING_TCPSERVER'], CPPPATH = include_path)
 
 Return('group')

+ 33 - 23
tcpserver.c

@@ -10,8 +10,12 @@
 
 #include "tcpserver.h"
 
-#define DBG_TAG              "tcpserv"
-#define DBG_LVL              DBG_LOG
+#define DBG_TAG    "tcpserv"
+#ifdef  PKG_TCPSERVER_DEBUG
+#define DBG_LVL    DBG_LOG
+#else
+#define DBG_LVL    DBG_INFO
+#endif
 #include <rtdbg.h>
 
 static tcpclient_t tcpserver_add_cli(struct tcpserver *serv, int fd_cli)
@@ -32,7 +36,7 @@ static tcpclient_t tcpserver_add_cli(struct tcpserver *serv, int fd_cli)
 
     client->server = serv;
     client->sock = fd_cli;
-    client->event = rt_event_create(TCP_SERV_NAME, RT_IPC_FLAG_FIFO);
+    client->event = rt_event_create(TCPSERVER_NAME, RT_IPC_FLAG_FIFO);
     if (client->event == RT_NULL)
     {
         LOG_E("client event create failed!");
@@ -60,7 +64,7 @@ static tcpclient_t tcpserver_add_cli(struct tcpserver *serv, int fd_cli)
     rt_mb_send(serv->mailbox, (rt_uint32_t)client);
     if (serv->tcpserver_event_notify)
     {
-        serv->tcpserver_event_notify(client, TCP_SERVER_EVENT_CONNECT);
+        serv->tcpserver_event_notify(client, TCPSERVER_EVENT_CONNECT);
     }
     return client;
 
@@ -108,7 +112,7 @@ static void tcpserver_del_cli(tcpclient_t client)
     /* notify disconnect */
     if (serv->tcpserver_event_notify)
     {
-        serv->tcpserver_event_notify(client, TCP_SERVER_EVENT_DISCONNECT);
+        serv->tcpserver_event_notify(client, TCPSERVER_EVENT_DISCONNECT);
     }
 
     /* free memory */
@@ -125,7 +129,7 @@ static void tcpserver_thread_entry(void *parameter)
     unsigned long ul = 1;
     struct timeval time = {0};
 
-    server->state = TCP_STATE_RUN;
+    server->state = TCPSERVER_STATE_RUN;
     server->fd_max = server->sock;
     time.tv_sec =  1;
     time.tv_usec = 0;
@@ -149,7 +153,7 @@ static void tcpserver_thread_entry(void *parameter)
         ret_sel = select(server->fd_max + 1, &read_set, &write_set, NULL, (void *)&time);
 
         /* detection stop mark */
-        if (server->state == TCP_STATE_STOP)
+        if (server->state == TCPSERVER_STATE_STOP)
         {
             LOG_D("server thread exit.");
             return;
@@ -191,10 +195,10 @@ static void tcpserver_thread_entry(void *parameter)
                 }
                 if (server->cli_list[i])
                 {
-                    rt_event_send(server->cli_list[i]->event, TCP_SERVER_EVENT_RECV);
+                    rt_event_send(server->cli_list[i]->event, TCPSERVER_EVENT_RECV);
                     if (server->tcpserver_event_notify)
                     {
-                        server->tcpserver_event_notify(server->cli_list[i], TCP_SERVER_EVENT_RECV);
+                        server->tcpserver_event_notify(server->cli_list[i], TCPSERVER_EVENT_RECV);
                     }
                 }
             }
@@ -214,7 +218,7 @@ rt_size_t tcpserver_recv(tcpclient_t client, void *buf, rt_size_t size, rt_int32
     RT_ASSERT(client);
     RT_ASSERT(buf != RT_NULL);
 
-    if (rt_event_recv(client->event, TCP_SERVER_EVENT_RECV,
+    if (rt_event_recv(client->event, TCPSERVER_EVENT_RECV,
                       RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
                       timeout, &e) == RT_EOK)
     {
@@ -267,7 +271,7 @@ void tcpserver_set_notify_callback(struct tcpserver *server, void (*tcpserver_ev
     server->tcpserver_event_notify = tcpserver_event_notify;
 }
 
-rt_err_t tcpserver_start(struct tcpserver *server)
+static rt_err_t tcpserver_start(struct tcpserver *server)
 {
     struct sockaddr_in addr;
     int ret_bind, ret_listen;
@@ -276,7 +280,7 @@ rt_err_t tcpserver_start(struct tcpserver *server)
     server->sock = socket(AF_INET, SOCK_STREAM, 0);
     if (server->sock < 0)
     {
-        LOG_E("socket");
+        LOG_E("socket create failed");
         return -1;
     }
 
@@ -293,27 +297,33 @@ rt_err_t tcpserver_start(struct tcpserver *server)
     ret_bind = bind(server->sock, (struct sockaddr *)&addr, sizeof(addr));
     if (ret_bind < 0)
     {
-        LOG_E("bind");
-        return -1;
+        LOG_E("bind failed");
+        goto __exit;
     }
 
-    ret_listen = listen(server->sock, TCP_SERVER_CLI_NUM);
+    ret_listen = listen(server->sock, TCPSERVER_CLI_NUM);
     if (ret_listen < 0)
     {
-        LOG_E("listen");
-        return -1;
+        LOG_E("listen failed");
+        goto __exit;
     }
 
-    server->thread = rt_thread_create(TCP_SERV_NAME,
+    server->thread = rt_thread_create(TCPSERVER_NAME,
                                       tcpserver_thread_entry, server,
-                                      TCP_SERV_STACK_SIZE, TCP_SERV_PRIO, 10);
+                                      TCPSERVER_STACK_SIZE, TCPSERVER_PRIO, 10);
 
     if (server->thread != NULL)
         rt_thread_startup(server->thread);
     else
+    {
         LOG_E("thread create failed");
-
+        goto __exit;
+    }
     return RT_EOK;
+__exit:
+    if(server->sock)
+        closesocket(server->sock);
+    return -1;
 }
 
 struct tcpserver *tcpserver_create(const char *ip, rt_uint16_t port)
@@ -326,13 +336,13 @@ struct tcpserver *tcpserver_create(const char *ip, rt_uint16_t port)
         LOG_E("no memory for tcp server");
         return RT_NULL;
     }
-    server->mailbox = rt_mb_create(TCP_SERV_NAME, TCP_SERVER_CLI_NUM, RT_IPC_FLAG_FIFO);
+    server->mailbox = rt_mb_create(TCPSERVER_NAME, TCPSERVER_CLI_NUM, RT_IPC_FLAG_FIFO);
     if (server->mailbox == RT_NULL)
     {
         LOG_E("no memory for mailbox");
         goto __exit;
     }
-    server->cli_list = (tcpclient_t *)rt_calloc(1, sizeof(tcpclient_t) * TCP_SERV_SOCKET_MAX);
+    server->cli_list = (tcpclient_t *)rt_calloc(1, sizeof(tcpclient_t) * TCPSERVER_SOCKET_MAX);
     if (server->cli_list == RT_NULL)
     {
         LOG_E("no memory for cli_list");
@@ -366,7 +376,7 @@ rt_err_t tcpserver_destroy(struct tcpserver *server)
     int i;
 
     /* wait for the select thread to exit */
-    server->state = TCP_STATE_STOP;
+    server->state = TCPSERVER_STATE_STOP;
     while (server->thread->stat != RT_THREAD_CLOSE)
     {
         rt_thread_mdelay(100);

+ 17 - 15
tcpserver.h

@@ -18,22 +18,24 @@
 #include <sys/select.h>
 #include <sys/time.h>
 
-#define TCP_SERV_NAME        "tcpserv"
-#define TCP_SERV_STACK_SIZE  4096
-#define TCP_SERV_PRIO        12
-#define TCP_SERV_SOCKET_MAX  1024
-
-#define TCP_STATE_INIT   0
-#define TCP_STATE_RUN    1
-#define TCP_STATE_STOP   2
-
-#define BUFSZ   1024
+/* configurable options */
+#ifndef PKG_USING_TCPSERVER
+#define TCPSERVER_NAME         "tcpserv"
+#define TCPSERVER_STACK_SIZE   4096
+#define TCPSERVER_PRIO         12
+#define TCPSERVER_SOCKET_MAX   1024
+#define TCPSERVER_CLI_NUM      5
+#endif
 
-#define TCP_SERVER_CLI_NUM   10
+/* run state */
+#define TCPSERVER_STATE_INIT   0
+#define TCPSERVER_STATE_RUN    1
+#define TCPSERVER_STATE_STOP   2
 
-#define TCP_SERVER_EVENT_CONNECT      (1 << 0)
-#define TCP_SERVER_EVENT_DISCONNECT   (1 << 1)
-#define TCP_SERVER_EVENT_RECV         (1 << 2)
+/* event flag */
+#define TCPSERVER_EVENT_CONNECT      (1 << 0)
+#define TCPSERVER_EVENT_DISCONNECT   (1 << 1)
+#define TCPSERVER_EVENT_RECV         (1 << 2)
 
 typedef struct tcpclient *tcpclient_t;
 
@@ -71,7 +73,7 @@ tcpclient_t tcpserver_accept(struct tcpserver *server, rt_int32_t timeout);
 rt_err_t tcpserver_close(tcpclient_t client);
 
 rt_size_t tcpserver_recv(tcpclient_t client, void *buf, rt_size_t size, rt_int32_t timeout);
-rt_size_t tcpserver_send(tcpclient_t client, void *buf, rt_size_t size, rt_int32_t timeout);
+rt_size_t tcpserver_send(tcpclient_t client, void *buf, rt_size_t size, rt_int32_t timeout); /* timeout unrealized */
 
 void tcpserver_set_notify_callback(struct tcpserver *server,
                                    void (*tcpserver_event_notify)(tcpclient_t client, rt_uint8_t event));

+ 64 - 0
tcpserver_sample.c

@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-07-11     flybreak     the first version
+ */
+
+#include "tcpserver.h"
+#include <string.h>
+
+#define DBG_TAG   "tcpserv"
+#define DBG_LVL   DBG_LOG
+#include <rtdbg.h>
+
+static struct tcpserver *serv;
+static rt_uint8_t buf[1024];
+
+static void tcpserver_event_notify(tcpclient_t client, rt_uint8_t event)
+{
+    int ret;
+    switch (event)
+    {
+    case TCPSERVER_EVENT_CONNECT:
+        LOG_D("client connect:%d", client->sock);
+        break;
+    case TCPSERVER_EVENT_RECV:
+        ret = tcpserver_recv(client, buf, 1024, -1);
+        if (ret > 0)
+        {
+            ret = tcpserver_send(client, buf, ret, 0);
+        }
+        break;
+    case TCPSERVER_EVENT_DISCONNECT:
+        LOG_D("client disconnect:%d", client->sock);
+        break;
+    default:
+        break;
+    }
+}
+
+static int tcpserver(int argc, char **argv)
+{
+    if (argc != 3)
+    {
+        rt_kprintf("Usage:./select_server [ip] [port]\n");
+        return -1;
+    }
+    serv = tcpserver_create(argv[1], atoi(argv[2]));
+
+    tcpserver_set_notify_callback(serv, tcpserver_event_notify);
+
+    return 0;
+}
+MSH_CMD_EXPORT(tcpserver, server start)
+
+static int tcpserver_stop(int argc, char **argv)
+{
+    tcpserver_destroy(serv);
+    return 0;
+}
+MSH_CMD_EXPORT(tcpserver_stop, tcpserver stop)