Linux usb 6. HC/UDC 测试
1. 背景介绍
在测试 USB 时,普通的做法是找一些 U 盘、鼠标、键盘 等外设来做一些测试,但是这些测试还是偏上层偏功能的。相比较 HC (USB Host Controller) 和 UDC (USB Device Controller) 按照USB协议提供的完整功能来说,这种测试验证时不充分的。
在 Linux Kernel 中对 HC/UDC 有一套专有的测试方案,在底层对 control/bulk/int/iso 几种 endpoint 进行针对性的功能和压力测试。
上图的测试方案由几部分组成:
- 1、Device 侧的
gadget zero
测试设备,提供了测试通道。 - 2、Host 侧的
usbtest.ko
测试驱动,封装了 30 个 endpoint 层级的测试用例。 - 3、Host 侧的
testusb
用户程序,用来调用usbtest.ko
提供的测试用例。
2. Device (gadget zero)
提供测试需要的Device设备有很多种方式,例如可用使用专门的测试 Device 里面烧录专有的测试 Firmware。节约成本的方式还是使用 Linux gadget 功能来动态模拟 USB Device 设备。针对 USB 测试,Linux 专门提供了 gadget zero
设备。
2.1 gadget zero
创建
gadget zero
的核心是创建一个 Composite Device
,其包含了两个 Configuration
,其中一个 Configuration 0
包含 SourceSink Function/Interface
,另一个 Configuration 1
包含 Loopback Function/Interface
。某一时刻只能选择使用一个 Configuration
,通常情况下使用 Configuration 0
即 SourceSink
的功能。
gadget zero
由两种方式创建:
- 1、通过
zero_driver
创建,只要把对应驱动文件drivers\usb\gadget\legacy\zero.c
编译进内核即可。 - 2、通过
functionfs
动态创建,这种方式更灵活,实例命令如下:
mount -t configfs none /sys/kernel/config
cd /sys/kernel/config/usb_gadget
mkdir g2
cd g2
echo "0x04e8" > idVendor
echo "0x2d01" > idProduct
mkdir configs/c.1
mkdir configs/c.2
mkdir functions/Loopback.0
mkdir functions/SourceSink.0
mkdir strings/0x409
mkdir configs/c.1/strings/0x409
mkdir configs/c.2/strings/0x409
echo "0x0525" > idVendor
echo "0xa4a0" > idProduct
echo "0123456789" > strings/0x409/serialnumber
echo "Samsung Inc." > strings/0x409/manufacturer
echo "Bar Gadget" > strings/0x409/product
echo "Conf 1" > configs/c.1/strings/0x409/configuration
echo "Conf 2" > configs/c.2/strings/0x409/configuration
echo 120 > configs/c.1/MaxPower
// SourceSink:驱动 set configuration 会选取 第一个 configuration
ln -s functions/Loopback.0 configs/c.2
ln -s functions/SourceSink.0 configs/c.1
echo 4100000.udc-controller > UDC
整个过程就是创建了一个 Vendor ID = 0x0525
、Product ID = 0xa4a0
的 Composite Device
,在 Host 侧可以查看这个设备:
$ lsusb-s 1:3
Bus 001 Device 003: ID 0525:a4a0 Netchip Technology, Inc. Linux-USB "Gadget Zero"
$ lsusb -v -s 1:3
Bus 001 Device 003: ID 0525:a4a0 Netchip Technology, Inc. Linux-USB "Gadget Zero"
Couldn't open device, some information will be missing
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x0525 Netchip Technology, Inc.
idProduct 0xa4a0 Linux-USB "Gadget Zero"
bcdDevice 5.10
iManufacturer 1
iProduct 2
iSerial 3
bNumConfigurations 2
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0045
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 4
bmAttributes 0x80
(Bus Powered)
MaxPower 120mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 1
bNumEndpoints 4
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0400 1x 1024 bytes
bInterval 4
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 1
Transfer Type Isochronous
Synch Type None
Usage Type Data
wMaxPacketSize 0x0400 1x 1024 bytes
bInterval 4
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0020
bNumInterfaces 1
bConfigurationValue 2
iConfiguration 5
bmAttributes 0x80
(Bus Powered)
MaxPower 2mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 6
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
2.2 SourceSink Function
SourceSink Function
的主要功能是提供了一组 USB 测试 endpoint,其中:
Sink
。sinks bulk packets OUT to the peripheral。意思是把数据从 Host 引流到 Device,即OUT
方向。Source
。sources them IN to the host。意思是把从 Device 发送数据到 Device,即IN
方向。
具体提供了 4 组 测试 endpoint:
Endpoint | Type | Direction | Descript |
---|---|---|---|
in_ep | bulk | IN | Source 发送数据到 Host,注意这数据是 Device 主动生成的 |
out_ep | bulk | OUT | Sink 接收 Host 的数据 |
iso_in_ep | iso | IN | Source 发送数据到 Host |
iso_out_ep | iso | OUT | Sink 接收 Host 的数据 |
主要流程如下:
drivers\usb\gadget\function\f_sourcesink.c:
sourcesink_bind():
static int
sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
{
/* (1) 从 gadget 中分配 2 个 bulk endpoint */
/* allocate bulk endpoints */
ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
ss->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc);
/* (2) 如果支持ISO,再从 gadget 中分配 2 个 iso endpoint */
/* allocate iso endpoints */
ss->iso_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_source_desc);
if (!ss->iso_in_ep)
goto no_iso;
ss->iso_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_sink_desc);
if (!ss->iso_out_ep) {
}
sourcesink_set_alt() → enable_source_sink() → usb_ep_enable()/source_sink_start_ep():
// 启动上述 endpoint
→ source_sink_complete():
// urb 的 complete() 函数,urb 发送/接收完成后,重新挂载 urb
还支持一些参数调整:
# ls functions/SourceSink.0/
bulk_buflen iso_qlen isoc_maxburst isoc_mult
bulk_qlen isoc_interval isoc_maxpacket pattern
2.3 Loopback Function
Loopback Function
提供的功能更为简单,它分配了两个 bulk endpoint,所做的就是把 out_ep
接收到的数据 转发到 in_ep
。
主要流程如下:
drivers\usb\gadget\function\f_loopback.c:
loopback_bind():
static int loopback_bind(struct usb_configuration *c, struct usb_function *f)
{
/* (1) 从 gadget 中分配 2 个 bulk endpoint */
/* allocate endpoints */
loop->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_source_desc);
loop->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_loop_sink_desc);
}
loopback_set_alt() → enable_loopback() → alloc_requests():
static int alloc_requests(struct usb_composite_dev *cdev,
struct f_loopback *loop)
{
for (i = 0; i < loop->qlen && result == 0; i++) {
result = -ENOMEM;
in_req = usb_ep_alloc_request(loop->in_ep, GFP_ATOMIC);
if (!in_req)
goto fail;
out_req = lb_alloc_ep_req(loop->out_ep, loop->buflen);
if (!out_req)
goto fail_in;
in_req->complete = loopback_complete;
out_req->complete = loopback_complete;
in_req->buf = out_req->buf;
/* length will be set in complete routine */
in_req->context = out_req;
out_req->context = in_req;
/* (2) 先启动 OUT endpoint */
result = usb_ep_queue(loop->out_ep, out_req, GFP_ATOMIC);
if (result) {
ERROR(cdev, "%s queue req --> %d\n",
loop->out_ep->name, result);
goto fail_out;
}
}
}
static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_loopback *loop = ep->driver_data;
struct usb_composite_dev *cdev = loop->function.config->cdev;
int status = req->status;
switch (status) {
case 0: /* normal completion? */
if (ep == loop->out_ep) {
/*
* We received some data from the host so let's
* queue it so host can read the from our in ep
*/
struct usb_request *in_req = req->context;
in_req->zero = (req->actual < req->length);
in_req->length = req->actual;
ep = loop->in_ep;
req = in_req;
} else {
/*
* We have just looped back a bunch of data
* to host. Now let's wait for some more data.
*/
req = req->context;
ep = loop->out_ep;
}
/* (3) 环回的关键:
OUT endpoint 接收到的数据 转发到 IN endpoint
IN endpoint 数据发送完成后 req 重新挂载到 OUT endpoint
*/
/* queue the buffer back to host or for next bunch of data */
status = usb_ep_queue(ep, req, GFP_ATOMIC);
}
也支持一些参数调整:
# ls functions/Loopback.0/
bulk_buflen qlen
3. Host (usbtest.ko)
在 Host 侧的 usbtest.ko
它就是一个标准的 usb interface driver
。它根据 Vendor ID = 0x0525
、Product ID = 0xa4a0
适配上一节 Composite Device
中的 SourceSink Interface
或者 Loopback Interface
。
static const struct usb_device_id id_table[] = {
/* "Gadget Zero" firmware runs under Linux */
{ USB_DEVICE(0x0525, 0xa4a0),
.driver_info = (unsigned long) &gz_info,
},
}
MODULE_DEVICE_TABLE(usb, id_table);
static struct usb_driver usbtest_driver = {
.name = "usbtest",
.id_table = id_table,
.probe = usbtest_probe,
.unlocked_ioctl = usbtest_ioctl,
.disconnect = usbtest_disconnect,
.suspend = usbtest_suspend,
.resume = usbtest_resume,
};
3.1 testcase
其在 SourceSink Interface
提供的 4 个测试 endpoint、或者 Loopback Interface
提供的 2 个测试 endpoint + Composite Device
本身的 ep0 control endpoint 基础之上,提供了30个 testcase:
drivers\usb\misc\usbtest.c:
usbtest_do_ioctl()
index | type | iterations | vary | sglen | unaligned | testcase | descript |
---|---|---|---|---|---|---|---|
0 | nop | - | - | - | - | "TEST 0: NOP\n" | - |
1 | bulk | Y | - | - | - | "TEST 1: write %d bytes %u times\n", param->length, param->iterations |
/* Simple non-queued bulk I/O tests */ |
2 | bulk | Y | - | - | - | "TEST 2: read %d bytes %u times\n", param->length, param->iterations |
- |
3 | bulk | Y | Y | - | - | "TEST 3: write/%d 0..%d bytes %u times\n", param->vary, param->length, param->iterations |
- |
4 | bulk | Y | Y | - | - | "TEST 4: read/%d 0..%d bytes %u times\n", param->vary, param->length, param->iterations |
- |
5 | bulk | Y | - | Y | - | "TEST 5: write %d sglists %d entries of %d bytes\n", param->iterations,param->sglen, param->length |
/* Queued bulk I/O tests */ |
6 | bulk | Y | - | Y | - | "TEST 6: read %d sglists %d entries of %d bytes\n", param->iterations,param->sglen, param->length |
- |
7 | bulk | Y | Y | Y | - | "TEST 7: write/%d %d sglists %d entries 0..%d bytes\n", param->vary, param->iterations,param->sglen, param->length |
- |
8 | bulk | Y | Y | Y | - | "TEST 8: read/%d %d sglists %d entries 0..%d bytes\n", param->vary, param->iterations,param->sglen, param->length |
- |
9 | control | Y | - | - | - | "TEST 9: ch9 (subset) control tests, %d times\n", param->iterations |
/* non-queued sanity tests for control (chapter 9 subset) */ |
10 | control | Y | - | Y | - | "TEST 10: queue %d control calls, %d times\n", param->sglen, param->iterations) |
/* queued control messaging */ |
11 | bulk | Y | - | - | - | "TEST 11: unlink %d reads of %d\n", param->iterations, param->length |
/* simple non-queued unlinks (ring with one urb) */ |
12 | bulk | Y | - | - | - | "TEST 12: unlink %d writes of %d\n", param->iterations, param->length |
- |
13 | control | Y | - | - | - | "TEST 13: set/clear %d halts\n" param->iterations |
/* ep halt tests */ |
14 | control | Y | Y | - | - | "TEST 14: %d ep0out, %d..%d vary %d\n", param->iterations,realworld ? 1 : 0, param->length,param->vary |
/* control write tests */ |
15 | iso | Y | - | Y | - | "TEST 15: write %d iso, %d entries of %d bytes\n", param->iterations, param->sglen, param->length |
/* iso write tests */ |
16 | iso | Y | - | Y | - | "TEST 16: read %d iso, %d entries of %d bytes\n", param->iterations, param->sglen, param->length |
/* iso read tests */ |
17 | bulk | Y | - | - | Y | "TEST 17: write odd addr %d bytes %u times core map\n" param->length, param->iterations |
/* Tests for bulk I/O using DMA mapping by core and odd address */ |
18 | bulk | Y | - | - | Y | "TEST 18: read odd addr %d bytes %u times core map\n", param->length, param->iterations |
- |
19 | bulk | Y | - | - | Y | "TEST 19: write odd addr %d bytes %u times premapped\n", param->length, param->iterations |
/* Tests for bulk I/O using premapped coherent buffer and odd address */ |
20 | bulk | Y | - | - | Y | "TEST 20: read odd addr %d bytes %u times premapped\n", param->length, param->iterations |
- |
21 | control | Y | Y | - | Y | "TEST 21: %d ep0out odd addr, %d..%d vary %d\n", param->iterations,realworld ? 1 : 0, param->length, param->vary |
/* control write tests with unaligned buffer */ |
22 | iso | Y | - | Y | Y | "TEST 22: write %d iso odd, %d entries of %d bytes\n", param->iterations, param->sglen, param->length |
/* unaligned iso tests */ |
23 | iso | Y | - | Y | Y | "TEST 23: read %d iso odd, %d entries of %d bytes\n", param->iterations, param->sglen, param->length |
- |
24 | bulk | Y | - | Y | - | "TEST 24: unlink from %d queues of %d %d-byte writes\n", param->iterations, param->sglen, param->length |
/* unlink URBs from a bulk-OUT queue */ |
25 | int | Y | - | - | - | "TEST 25: write %d bytes %u times\n", param->length, param->iterations |
/* Simple non-queued interrupt I/O tests */ |
26 | int | Y | - | - | - | "TEST 26: read %d bytes %u times\n", param->length, param->iterations |
- |
27 | bulk | Y | - | Y | - | "TEST 27: bulk write %dMbytes\n", (param->iterations * param->sglen * param->length) / (1024 * 1024)) |
/* Performance test */ |
28 | bulk | Y | - | Y | - | "TEST 28: bulk read %dMbytes\n", (param->iterations * param->sglen * param->length) / (1024 * 1024)) |
- |
29 | bulk | Y | - | - | - | "TEST 29: Clear toggle between bulk writes %d times\n", param->iterations |
/* Test data Toggle/seq_nr clear between bulk out transfers */ |
3.2 ioctl
usbtest.ko
以 ioctl 的形式向用户态提供对 testcase 的调用:
usbdev_file_operations → usbdev_ioctl() → usbdev_do_ioctl() → proc_ioctl_default() → proc_ioctl():
static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)
{
/* (1) 找到对应的 usb interface device */
else if (!(intf = usb_ifnum_to_if(ps->dev, ctl->ifno)))
retval = -EINVAL;
/* talk directly to the interface's driver */
default:
if (intf->dev.driver)
/* (2) 找到 usb interface device 对应的 driver */
driver = to_usb_driver(intf->dev.driver);
if (driver == NULL || driver->unlocked_ioctl == NULL) {
retval = -ENOTTY;
} else {
/* (3) 调用 driver 的 ioctl 函数 */
retval = driver->unlocked_ioctl(intf, ctl->ioctl_code, buf);
if (retval == -ENOIOCTLCMD)
retval = -ENOTTY;
}
}
↓
usbtest_ioctl() → usbtest_do_ioctl()
4. App (testusb)
因为通过 ioctl 可以调用 usbtest.ko
的 testcase,所以只要一个用户态的程序通过打开 /proc/bus/usb/devices/xxxx
对应 gadget zero
的 usb interface device
的文件节点,就可以很方便的调用测试了。
在 USB Testing on Linux 有一个现成的工程,提供了 testusb.c 和 test.sh,但是因为适配的内核比较老,所以需要对 testusb.c
进行一些修改:
- if ((c = open ("/proc/bus/usb/devices", O_RDONLY)) < 0) {
+ if ((c = open ("/sys/kernel/debug/usb/devices", O_RDONLY)) < 0) {
fputs ("usbfs files are missing\n", stderr);
return -1;
}
/* collect and list the test devices */
- if (ftw ("/proc/bus/usb", find_testdev, 3) != 0) {
+ if (ftw ("/dev/bus/usb", find_testdev, 3) != 0) {
fputs ("ftw failed; is usbfs missing?\n", stderr);
return -1;
}
简单编译:
gcc -Wall -g -lpthread -o testusb testusb.c
就可以启动测试了:
$ sudo ./testusb -a
unknown speed /dev/bus/usb/001/002
/dev/bus/usb/001/002 test 0, 0.000011 secs
/dev/bus/usb/001/002 test 1, 1.625031 secs
/dev/bus/usb/001/002 test 2 --> 110 (Connection timed out)
/dev/bus/usb/001/002 test 3, 1.639717 secs
/dev/bus/usb/001/002 test 4 --> 110 (Connection timed out)
/dev/bus/usb/001/002 test 5, 1.915198 secs
/dev/bus/usb/001/002 test 6 --> 110 (Connection timed out)
/dev/bus/usb/001/002 test 7, 1.928419 secs
/dev/bus/usb/001/002 test 8 --> 110 (Connection timed out)
/dev/bus/usb/001/002 test 9, 13.835084 secs
sudo ./testusb -a
sudo ./testusb -a -t1 -c1 -s512 -g32 -v32
sudo ./testusb -a -t29 -c1 -s512 -g32 -v32
// test 10 需要特别注意,容易挂死 host
sudo ./testusb -a -t10 -c1 -s512 -g5 -v32
// test 28 需要特别注意,容易挂死 host
sudo ./testusb -a -t28 -c1 -s512 -g32 -v32
参考资料
1.USB Testing on Linux
2.Linux USB测试
3.linux usb_gadget:设备控制器驱动测试
4.Linux-USB Gadget : Part 5: 测试 PXA UDC 驱动
5.Linux-USB Gadget : Part 4: 最简单的 gadget驱动:g_zero
6.Linux USB tests using Gadget Zero driver
7.USB/Linux USB Layers/Configfs Composite Gadget/Usage eq. to g zero.ko
8.usb/gadget: the start of the configfs interface
Linux usb 6. HC/UDC 测试的更多相关文章
- kali Linux下wifi密码安全测试(1)虚拟机下usb无线网卡的挂载 【转】
转自:http://blog.chinaunix.net/uid-26349264-id-4455634.html 目录 kali Linux下wifi密码安全测试(1)虚拟机下usb无线网卡的挂载 ...
- Linux usb子系统(一):子系统架构
一.USB协议基础知识 前序:USB概念概述 USB1.0版本速度1.5Mbps(低速USB) USB1.1版本速度12Mbps(全速USB) USB2.0版本速度480Mbps(高速USB). ...
- Linux USB驱动框架分析 【转】
转自:http://blog.chinaunix.net/uid-11848011-id-96188.html 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结 ...
- 《网蜂A8实战演练》——8.Linux USB 主机控制器和设备驱动
USB 的全称是 Universal Serial Bus,顾名思义:通用串行总线. 提到总线,联想一下,在你心目中总线总是用来干嘛的?还记得 I2C 总线? I2C 总线上挂有二条信号线,一条是 S ...
- Linux USB驱动框架分析【转】
转自:http://blog.csdn.net/jeffade/article/details/7701431 Linux USB驱动框架分析(一) 初次接触和OS相关的设备驱动编写,感觉还挺有意思的 ...
- linux USB 编程
Linux USB架构 可以看出一个USB体系需要4个驱动:USB设备驱动(主要编写这部分),USB主控制器驱动,Gadget驱动,UDC驱动. USB主要有4个功能: MassStorage:大容量 ...
- linux usb驱动记录(一)
一.linux 下的usb驱动框架 在linux系统中,usb驱动可以从两个角度去观察,一个是主机侧,一个是设备侧.linux usb 驱动的总体框架如下图所示: 从主机侧看usb驱动可分为四层: ...
- Linux USB 鼠标驱动程序详解(转)
Linux USB 鼠标驱动程序详解 USB 总线引出两个重要的链表!一个 USB 总线引出两个重要的链表,一个为 USB 设备链表,一个为 USB 驱动链表.设备链表包含各种系统中的 USB 设备以 ...
- Linux USB Project
转自:http://www.linux-usb.org/ Welcome to the home of the Linux USB Project This web site was created ...
随机推荐
- 鸿蒙内核源码分析(线程概念篇) | 是谁在不停的折腾CPU? | 百篇博客分析OpenHarmony源码 | v21.06
百篇博客系列篇.本篇为: v21.xx 鸿蒙内核源码分析(线程概念篇) | 是谁在不断的折腾CPU | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调 ...
- Python3入门系列之-----函数
什么是函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但你也可以自己 ...
- 看动画学算法之:doublyLinkedList
目录 简介 doublyLinkedList的构建 doublyLinkedList的操作 头部插入 尾部插入 插入给定的位置 删除指定位置的节点 简介 今天我们来学习一下复杂一点的LinkedLis ...
- Vulnhub实战-doubletrouble靶机👻
Vulnhub实战-doubletrouble靶机 靶机下载地址:https://www.vulnhub.com/entry/doubletrouble-1,743/ 下载页面的ova格式文件导入vm ...
- css超出隐藏显示省略号怎么设置?
当我们在进行网页前端开发的时候,一般获取文章标题,然后一行一行的显示.但是当标题过长的时候,就会造成换行显示.还有显示部分文本信息时,如果全部显示就过于繁琐,会带来不会的网页体验感.虽然我们可以使用o ...
- 解决VSCODE"因为在此系统上禁止运行脚本"报错
在VSCODE中使用yarn,结果报错: 找了下原因,是因为PowerShell执行策略的问题. 解决方法: 以管理员身份运行vscode; 执行:get-ExecutionPolicy,显示R ...
- LOJ6356 四色灯(容斥+dp
纪念第一次所有的解析全写在代码里面 QWQ 这里就简单说几句了 首先一个灯有贡献,当且仅当他被按了\(4k\)次. 那么我们定义\(f(S)\)表示\([1,n]\)中有多少个数\(x\)是集合\(S ...
- Netty 进阶
1. 粘包与半包 1.1 粘包现象 服务端代码 public class HelloWorldServer { static final Logger log = LoggerFactory.getL ...
- 这么多TiDB负载均衡方案总有一款适合你
[是否原创]是 [首发渠道]TiDB 社区 前言 分布式关系型数据库TiDB是一种计算和存储分离的架构,每一层都可以独立地进行水平扩展,这样就可以做到有的放矢,对症下药. 从TiDB整体架构图可以看到 ...
- 以太坊web3开发初步学习
以太坊web3开发初步学习 此文是对https://learnblockchain.cn/2018/04/15/web3-html/的学习再理解. 以太坊智能合约通过使用web3.js前端和智能合约交 ...