This commit is contained in:
刘可亮
2024-01-27 08:47:24 +08:00
parent d3bd993b5f
commit 9f7ba67007
2345 changed files with 74421 additions and 76616 deletions

16
packages/third-party/netutils/Kconfig vendored Normal file
View File

@@ -0,0 +1,16 @@
menuconfig LPKG_USING_NETUTILS
bool "netutils: Networking utilities for RT-Thread"
default n
if LPKG_USING_NETUTILS
config LPKG_NETUTILS_IPERF
bool "Enable iperf-liked network performance tool"
select RT_USING_LIBC if RT_VER_NUM < 0x40100
select RT_USING_SAL if RT_VER_NUM < 0x40100
select SAL_USING_POSIX if RT_VER_NUM < 0x40100
select RT_USING_POSIX_FS if RT_VER_NUM >= 0x40100
select RT_USING_POSIX_SOCKET if RT_VER_NUM >= 0x40100
default n
endif

View File

@@ -0,0 +1,15 @@
Import('AIC_ROOT')
Import('PRJ_KERNEL')
import os
from building import *
cwd = GetCurrentDir()
objs = []
list = os.listdir(cwd)
for d in list:
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, 'SConscript')):
objs = objs + SConscript(os.path.join(d, 'SConscript'))
Return('objs')

View File

@@ -0,0 +1,118 @@
# iperf: Network bandwidth test tool
## 1 Introduction
[iperf](https://baike.baidu.com/item/iperf) is a network performance testing tool. iperf can test the maximum TCP and UDP bandwidth performance, has a variety of parameters and UDP characteristics, can be adjusted as needed, can report bandwidth, delay jitter and packet loss.
## 2. Use
iperf uses a master-slave architecture, that is, one end is a server, and the other end is a client. The iperf component package we provide implements the TCP server mode and the client mode. UDP testing is not currently supported. The usage of the two modes will be explained in detail below.
### 2.1 iperf server mode
#### 2.1.1 Get IP address
You need to use Finsh/MSH commands on RT-Thread to obtain an IP address. The general effect is as follows:
```
msh />ifconfig
network interface: e0 (Default)
MTU: 1500
MAC: 00 04 9f 05 44 e5
FLAGS: UP LINK_UP ETHARP
ip address: 192.168.12.71
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
```
-Write down the obtained IP address 192.168.12.71 (record according to the actual situation)
#### 2.1.2 Start iperf server
You need to use Finsh/MSH commands on RT-Thread to start the iperf server. The general effect is as follows:
tcp mode
```
msh />iperf -s -p 5001
```
udp mode
```
msh />iperf -u -s -p 5001
```
- -s means to start as a server
- -p means to monitor port 5001
#### 2.1.3 Install JPerf test software
The installation file is located in `/tools/jperf.rar`, this is a green software, the installation is actually a process of decompression, just unzip it to a new folder.
#### 2.1.4 Perform jperf test
Open the `jperf.bat` software and configure as follows:
- Select `Client` mode
- Enter the IP address 192.168.12.71 just obtained (fill in according to the actual address)
- Modify the port number to 5001
- Click `run Lperf!` to start the test
- Wait for the test to end. During the test, the test data will be displayed on the shell interface and JPerf software.
TCP mode software settings
![iperfs](../images/iperfs.png)
udp mode software settings
![iperfs-udp](../images/iperfs-udp.png)
### 2.2 iperf client mode
#### 2.2.1 Get the IP address of the PC
Use the ipconfig command on the command prompt window of the PC to obtain the IP address of the PC, and write down the obtained PC IP address as 192.168.12.45 (record according to the actual situation).
#### 2.2.2 Install JPerf test software
The installation file is located in `/tools/jperf.rar`, this is a green software, the installation is actually a process of decompression, just unzip it to a new folder.
#### 2.2.3 Start jperf server
Open the `jperf.bat` software and configure as follows:
- Select `Server` mode
- Modify the port number to 5001
- Click `run Lperf!` to start the server
#### 2.2.4 Start iperf client
You need to use Finsh/MSH commands on RT-Thread to start the iperf client. The general effect is as follows:
tcp mode
```
msh />iperf -c 192.168.12.45 -p 5001
```
udp mode
```
msh />iperf -u -c 192.168.12.45 -p 5001
```
- -c means to start as a client, and then need to add the IP address of the pc running the server
- -p means to connect to port 5001
- Wait for the test to end. During the test, the test data will be displayed on the shell interface and JPerf software.
TCP mode software settings
![iperfc](../images/iperfc.png)
udp mode software settings
![iperfc-udp](../images/iperfc-udp.png)

View File

@@ -0,0 +1,117 @@
# iperf网络带宽测试工具
## 1、介绍
[iperf](https://baike.baidu.com/item/iperf) 是一个网络性能测试工具。iperf 可以测试最大 TCP 和 UDP 带宽性能,具有多种参数和 UDP 特性,可以根据需要调整,可以报告带宽、延迟抖动和数据包丢失。
## 2、使用
iperf 使用的是主从式架构,即一端是服务器,另一端是客户端,我们提供的 iperf 组件包实现了 TCP 服务器模式和客户端模式,暂不支持 UDP 测试。下面将具体讲解 2 种模式的使用方法。
### 2.1 iperf 服务器模式
#### 2.1.1 获取 IP 地址
需要在 RT-Thread 上使用 Finsh/MSH 命令来获取 IP 地址,大致效果如下:
```
msh />ifconfig
network interface: e0 (Default)
MTU: 1500
MAC: 00 04 9f 05 44 e5
FLAGS: UP LINK_UP ETHARP
ip address: 192.168.12.71
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
```
- 记下获得的 IP 地址 192.168.12.71(按实际情况记录)
#### 2.1.2 启动 iperf 服务器
需要在 RT-Thread 上使用 Finsh/MSH 命令来启动 iperf 服务器,大致效果如下:
tcp 模式
```
msh />iperf -s -p 5001
```
udp 模式
```
msh />iperf -u -s -p 5001
```
- -s 表示作为服务器启动
- -p 表示监听 5001 端口
#### 2.1.3 安装 JPerf 测试软件
安装文件位于 `/tools/jperf.rar` ,这个是绿色软件,安装实际上是解压的过程,解压到新文件夹即可。
#### 2.1.4 进行 jperf 测试
打开 `jperf.bat`软件,按如下操作进行配置:
- 选择 `Client` 模式
- 输入刚刚获得的 IP 地址 192.168.12.71(按实际地址填写)
- 修改端口号为 5001
- 点击 `run Lperf!` 开始测试
- 等待测试结束。测试时,测试数据会在 shell 界面和 JPerf 软件上显示。
tcp 模式软件设置
![iperfs](../images/iperfs.png)
udp 模式软件设置
![iperfs-udp](../images/iperfs-udp.png)
### 2.2 iperf 客户端模式
#### 2.2.1 获取 PC 的 IP 地址
在 PC 的命令提示符窗口上使用 ipconfig 命令获取 PC 的 IP 地址,记下获得的 PC IP 地址为 192.168.12.45(按实际情况记录)。
#### 2.2.2 安装 JPerf 测试软件
安装文件位于 `/tools/jperf.rar` ,这个是绿色软件,安装实际上是解压的过程,解压到新文件夹即可。
#### 2.2.3 开启 jperf 服务器
打开 `jperf.bat`软件,按如下操作进行配置:
- 选择 `Server` 模式
- 修改端口号为 5001
- 点击 `run Lperf!` 开启服务器
#### 2.2.4 启动 iperf 客户端
需要在 RT-Thread 上使用 Finsh/MSH 命令来启动 iperf 客户端,大致效果如下:
tcp 模式
```
msh />iperf -c 192.168.12.45 -p 5001
```
udp 模式
```
msh />iperf -u -c 192.168.12.45 -p 5001
```
- -c 表示作为客户端启动后面需要加运行服务器端的pc的 IP 地址
- -p 表示连接 5001 端口
- 等待测试结束。测试时,测试数据会在 shell 界面和 JPerf 软件上显示。
tcp 模式软件设置
![iperfc](../images/iperfc.png)
udp 模式软件设置
![iperfc-udp](../images/iperfc-udp.png)

View File

@@ -0,0 +1,7 @@
from building import *
src = Glob('*.c')
group = DefineGroup('iperf', src, depend = ['LPKG_NETUTILS_IPERF'])
Return('group')

View File

@@ -0,0 +1,522 @@
/**
* iperf-liked network performance tool
*
*/
#include <rtthread.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netdb.h>
#define DBG_SECTION_NAME "iperf"
#define DBG_LEVEL DBG_INFO
#include <rtdbg.h>
#define IPERF_PORT 5001
#define IPERF_BUFSZ (4 * 1024)
#define IPERF_MODE_STOP 0
#define IPERF_MODE_SERVER 1
#define IPERF_MODE_CLIENT 2
typedef struct
{
int mode;
char *host;
int port;
} IPERF_PARAM;
static IPERF_PARAM param = {IPERF_MODE_STOP, NULL, IPERF_PORT};
static void iperf_udp_client(void *thread_param)
{
int sock;
rt_uint32_t *buffer;
struct sockaddr_in server;
rt_uint32_t packet_count = 0;
rt_uint32_t tick;
int send_size;
send_size = IPERF_BUFSZ > 1470 ? 1470 : IPERF_BUFSZ;
buffer = rt_malloc(IPERF_BUFSZ);
if (buffer == NULL)
{
return;
}
memset(buffer, 0x00, IPERF_BUFSZ);
sock = socket(PF_INET, SOCK_DGRAM, 0);
if(sock < 0)
{
LOG_E("can't create socket! exit!");
return;
}
server.sin_family = PF_INET;
server.sin_port = htons(param.port);
server.sin_addr.s_addr = inet_addr(param.host);
LOG_I("iperf udp mode run...");
while (param.mode != IPERF_MODE_STOP)
{
packet_count++;
tick = rt_tick_get();
buffer[0] = htonl(packet_count);
buffer[1] = htonl(tick / RT_TICK_PER_SECOND);
buffer[2] = htonl((tick % RT_TICK_PER_SECOND) * 1000);
sendto(sock, buffer, send_size, 0, (struct sockaddr *)&server, sizeof(struct sockaddr_in));
}
closesocket(sock);
rt_free(buffer);
}
static void iperf_udp_server(void *thread_param)
{
int sock;
rt_uint32_t *buffer;
struct sockaddr_in server;
struct sockaddr_in sender;
int sender_len, r_size;
rt_uint64_t sentlen;
rt_uint32_t pcount = 0, last_pcount = 0;
rt_uint32_t lost, total;
rt_tick_t tick1, tick2;
struct timeval timeout;
buffer = rt_malloc(IPERF_BUFSZ);
if (buffer == NULL)
{
return;
}
sock = socket(PF_INET, SOCK_DGRAM, 0);
if(sock < 0)
{
LOG_E("can't create socket! exit!");
return;
}
server.sin_family = PF_INET;
server.sin_port = htons(param.port);
server.sin_addr.s_addr = inet_addr("0.0.0.0");
timeout.tv_sec = 2;
timeout.tv_usec = 0;
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == -1)
{
LOG_E("setsockopt failed!");
closesocket(sock);
rt_free(buffer);
return;
}
if (bind(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) < 0)
{
LOG_E("iperf server bind failed! exit!");
closesocket(sock);
rt_free(buffer);
return;
}
while (param.mode != IPERF_MODE_STOP)
{
tick1 = rt_tick_get();
tick2 = tick1;
lost = 0;
total = 0;
sentlen = 0;
while ((tick2 - tick1) < (RT_TICK_PER_SECOND * 5))
{
r_size = recvfrom(sock, buffer, IPERF_BUFSZ, 0, (struct sockaddr *)&sender, (socklen_t*)&sender_len);
if (r_size > 12)
{
pcount = ntohl(buffer[0]);
if (last_pcount < pcount)
{
lost += pcount - last_pcount - 1;
total += pcount - last_pcount;
}
else
{
last_pcount = pcount;
}
last_pcount = pcount;
sentlen += r_size;
}
tick2 = rt_tick_get();
}
if (sentlen > 0)
{
long data;
int integer, decimal;
rt_thread_t tid;
tid = rt_thread_self();
data = sentlen * RT_TICK_PER_SECOND / 125 / (tick2 - tick1);
integer = data/1000;
decimal = data%1000;
LOG_I("%s: %d.%03d0 Mbps! lost:%d total:%d\n", tid->name, integer, decimal, lost, total);
}
}
rt_free(buffer);
closesocket(sock);
}
static void iperf_client(void *thread_param)
{
int i;
int sock;
int ret;
int tips = 1;
uint8_t *send_buf;
rt_uint64_t sentlen;
rt_tick_t tick1, tick2;
struct sockaddr_in addr;
send_buf = (uint8_t *) rt_malloc(IPERF_BUFSZ);
if (!send_buf) return ;
for (i = 0; i < IPERF_BUFSZ; i ++)
send_buf[i] = i & 0xff;
while (param.mode != IPERF_MODE_STOP)
{
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0)
{
LOG_E("create socket failed!");
rt_thread_delay(RT_TICK_PER_SECOND);
continue;
}
addr.sin_family = PF_INET;
addr.sin_port = htons(param.port);
addr.sin_addr.s_addr = inet_addr((char *)param.host);
ret = connect(sock, (const struct sockaddr *)&addr, sizeof(addr));
if (ret == -1)
{
if (tips)
{
LOG_E("Connect to iperf server faile, Waiting for the server to open!");
tips = 0;
}
closesocket(sock);
rt_thread_delay(RT_TICK_PER_SECOND);
continue;
}
LOG_I("Connect to iperf server successful!");
{
int flag = 1;
setsockopt(sock,
IPPROTO_TCP, /* set option at TCP level */
TCP_NODELAY, /* name of option */
(void *) &flag, /* the cast is historical cruft */
sizeof(int)); /* length of option value */
}
sentlen = 0;
tick1 = rt_tick_get();
while (param.mode != IPERF_MODE_STOP)
{
tick2 = rt_tick_get();
if (tick2 - tick1 >= RT_TICK_PER_SECOND * 5)
{
long data;
int integer, decimal;
rt_thread_t tid;
tid = rt_thread_self();
data = sentlen * RT_TICK_PER_SECOND / 125 / (tick2 - tick1);
integer = data/1000;
decimal = data%1000;
LOG_I("%s: %d.%03d0 Mbps!", tid->name, integer, decimal);
tick1 = tick2;
sentlen = 0;
}
ret = send(sock, send_buf, IPERF_BUFSZ, 0);
if (ret > 0)
{
sentlen += ret;
}
if (ret < 0) break;
}
closesocket(sock);
rt_thread_delay(RT_TICK_PER_SECOND * 2);
LOG_W("Disconnected, iperf server shut down!");
tips = 1;
}
rt_free(send_buf);
}
void iperf_server(void *thread_param)
{
uint8_t *recv_data;
socklen_t sin_size;
rt_tick_t tick1, tick2;
int sock = -1, connected, bytes_received;
rt_uint64_t recvlen;
struct sockaddr_in server_addr, client_addr;
fd_set readset;
struct timeval timeout;
recv_data = (uint8_t *)rt_malloc(IPERF_BUFSZ);
if (recv_data == RT_NULL)
{
LOG_E("No memory!");
goto __exit;
}
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
LOG_E("Socket error!");
goto __exit;
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(param.port);
server_addr.sin_addr.s_addr = INADDR_ANY;
memset(&(server_addr.sin_zero), 0x0, sizeof(server_addr.sin_zero));
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
{
LOG_E("Unable to bind!");
goto __exit;
}
if (listen(sock, 5) == -1)
{
LOG_E("Listen error!");
goto __exit;
}
timeout.tv_sec = 3;
timeout.tv_usec = 0;
while (param.mode != IPERF_MODE_STOP)
{
FD_ZERO(&readset);
FD_SET(sock, &readset);
if (select(sock + 1, &readset, RT_NULL, RT_NULL, &timeout) == 0)
continue;
sin_size = sizeof(struct sockaddr_in);
connected = accept(sock, (struct sockaddr *)&client_addr, &sin_size);
LOG_I("new client connected from (%s, %d)",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
{
int flag = 1;
setsockopt(connected,
IPPROTO_TCP, /* set option at TCP level */
TCP_NODELAY, /* name of option */
(void *) &flag, /* the cast is historical cruft */
sizeof(int)); /* length of option value */
}
recvlen = 0;
tick1 = rt_tick_get();
while (param.mode != IPERF_MODE_STOP)
{
bytes_received = recv(connected, recv_data, IPERF_BUFSZ, 0);
if (bytes_received <= 0) break;
recvlen += bytes_received;
tick2 = rt_tick_get();
if (tick2 - tick1 >= RT_TICK_PER_SECOND * 5)
{
long data;
int integer, decimal;
rt_thread_t tid;
tid = rt_thread_self();
data = recvlen * RT_TICK_PER_SECOND / 125 / (tick2 - tick1);
integer = data/1000;
decimal = data%1000;
LOG_I("%s: %d.%03d0 Mbps!", tid->name, integer, decimal);
tick1 = tick2;
recvlen = 0;
}
}
LOG_W("client disconnected (%s, %d)",
inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
if (connected >= 0) closesocket(connected);
connected = -1;
}
__exit:
if (sock >= 0) closesocket(sock);
if (recv_data) rt_free(recv_data);
}
void iperf_usage(void)
{
rt_kprintf("Usage: iperf [-s|-c host] [options] [multi-threaded]\n");
rt_kprintf(" iperf [-h|--stop]\n");
rt_kprintf("\n");
rt_kprintf("Client/Server:\n");
rt_kprintf(" -p # server port to listen on/connect to\n");
rt_kprintf("\n");
rt_kprintf("Server specific:\n");
rt_kprintf(" -s run in server mode\n");
rt_kprintf("\n");
rt_kprintf("Client specific:\n");
rt_kprintf(" -c <host> run in client mode, connecting to <host>\n");
rt_kprintf("\n");
rt_kprintf("Miscellaneous:\n");
rt_kprintf(" -h print this message and quit\n");
rt_kprintf(" --stop stop iperf program\n");
rt_kprintf(" -u testing UDP protocol\n");
rt_kprintf(" -m <time> the number of multi-threaded ");
return;
}
int iperf(int argc, char **argv)
{
int mode = 0; /* server mode */
char *host = NULL;
int port = IPERF_PORT;
int numtid = 1;
int use_udp = 0;
int index = 1;
if (argc == 1)
{
goto __usage;
}
if (strcmp(argv[1], "-u") == 0)
{
index = 2;
use_udp = 1;
}
if (strcmp(argv[index], "-h") == 0) goto __usage;
else if (strcmp(argv[index], "--stop") == 0)
{
/* stop iperf */
param.mode = IPERF_MODE_STOP;
return 0;
}
else if (strcmp(argv[index], "-s") == 0)
{
mode = IPERF_MODE_SERVER; /* server mode */
/* iperf -s -p 5000 */
if (argc >= 4)
{
if (strcmp(argv[index + 1], "-p") == 0)
{
port = atoi(argv[index + 2]);
}
else goto __usage;
}
}
else if (strcmp(argv[index], "-c") == 0)
{
mode = IPERF_MODE_CLIENT; /* client mode */
if (argc < 3) goto __usage;
host = argv[index + 1];
if (argc >= 5)
{
/* iperf -c host -p port */
if (strcmp(argv[index + 2], "-p") == 0)
{
port = atoi(argv[index + 3]);
}
else goto __usage;
}
}
else goto __usage;
if (argc >= 7)
{
if(strcmp(argv[argc - 2], "-m") == 0)
{
numtid = atoi(argv[argc - 1]);
}
else goto __usage;
}
/* start iperf */
if (param.mode == IPERF_MODE_STOP)
{
int i = 0;
char tid_name[RT_NAME_MAX + 1] = {0};
param.mode = mode;
param.port = port;
if (param.host)
{
rt_free(param.host);
param.host = NULL;
}
if (host) param.host = rt_strdup(host);
for (i = 0; i < numtid; i++)
{
rt_thread_t tid = RT_NULL;
void (*function)(void *parameter);
if (use_udp)
{
if (mode == IPERF_MODE_CLIENT)
{
rt_snprintf(tid_name, sizeof(tid_name), "iperfc%02d", i + 1);
function = iperf_udp_client;
}
else if (mode == IPERF_MODE_SERVER)
{
rt_snprintf(tid_name, sizeof(tid_name), "iperfd%02d", i + 1);
function = iperf_udp_server;
}
}
else
{
if (mode == IPERF_MODE_CLIENT)
{
rt_snprintf(tid_name, sizeof(tid_name), "iperfc%02d", i + 1);
function = iperf_client;
}
else if (mode == IPERF_MODE_SERVER)
{
rt_snprintf(tid_name, sizeof(tid_name), "iperfd%02d", i + 1);
function = iperf_server;
}
}
tid = rt_thread_create(tid_name, function, RT_NULL, 2048, 20, 100);
if (tid) rt_thread_startup(tid);
}
}
else
{
rt_kprintf("Please stop iperf firstly, by:\n");
rt_kprintf("iperf --stop\n");
}
return 0;
__usage:
iperf_usage();
return 0;
}
#ifdef FINSH_USING_MSH
#include <finsh.h>
MSH_CMD_EXPORT(iperf, the network bandwidth measurement tool);
#endif

View File

@@ -0,0 +1,72 @@
{
"name": "netutils",
"description": "Networking utilities for RT-Thread",
"description_zh": "RT-Thread 网络网络小工具集",
"enable": "PKG_USING_NETUTILS",
"keywords": [
"netutils",
"lwip",
"net",
"ntp",
"tftp",
"iperf",
"telnet",
"netio",
"tcpdump"
],
"category": "iot",
"author": {
"name": "RealThread",
"email": "package_team@rt-thread.com",
"github": "RT-Thread-packages"
},
"license": "Apache-2.0",
"repository": "https://github.com/RT-Thread-packages/netutils",
"icon": "https://www.rt-thread.org/qa/template/fxiaomi/style/image/logo.png",
"homepage": "https://github.com/RT-Thread-packages/netutils#readme",
"doc": "https://www.rt-thread.org/document/site/rtthread-application-note/packages/netutils/an0018-rtthread-system-netutils/",
"site": [
{
"version": "v1.3.2",
"URL": "https://github.com/RT-Thread-packages/netutils/archive/1.3.2.zip",
"filename": "netutils-1.3.2.zip",
"VER_SHA": "NULL"
},
{
"version": "v1.3.1",
"URL": "https://github.com/RT-Thread-packages/netutils/archive/1.3.1.zip",
"filename": "netutils-1.3.1.zip",
"VER_SHA": "NULL"
},
{
"version": "v1.3.0",
"URL": "https://github.com/RT-Thread-packages/netutils/archive/1.3.0.zip",
"filename": "netutils-1.3.0.zip",
"VER_SHA": "NULL"
},
{
"version": "v1.2.0",
"URL": "https://github.com/RT-Thread-packages/netutils/archive/1.2.0.zip",
"filename": "netutils-1.2.0.zip",
"VER_SHA": "NULL"
},
{
"version": "v1.1.0",
"URL": "https://github.com/RT-Thread-packages/netutils/archive/1.1.0.zip",
"filename": "netutils-1.1.0.zip",
"VER_SHA": "NULL"
},
{
"version": "v1.0.0",
"URL": "https://github.com/RT-Thread-packages/netutils/archive/1.0.0.zip",
"filename": "netutils-1.0.0.zip",
"VER_SHA": "NULL"
},
{
"version": "latest",
"URL": "https://github.com/RT-Thread-packages/netutils.git",
"filename": "netutils.zip",
"VER_SHA": "master"
}
]
}