热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Linuxusb6.HC/UDC测试

文章目录1.背景介绍2.Device(gadgetzero)2.1gadgetzero创建2.2SourceSinkFunction2.3LoopbackFunction3.Hos


文章目录

  • 1. 背景介绍
  • 2. Device (gadget zero)
    • 2.1 `gadget zero` 创建
    • 2.2 SourceSink Function
    • 2.3 Loopback Function
  • 3. Host (usbtest.ko)
    • 3.1 testcase
    • 3.2 ioctl
  • 4. App (testusb)
  • 参考资料


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 0SourceSink的功能。

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_gadgetmkdir g2
cd g2echo "0x04e8" > idVendor
echo "0x2d01" > idProductmkdir configs/c.1
mkdir configs/c.2
mkdir functions/Loopback.0
mkdir functions/SourceSink.0mkdir strings/0x409
mkdir configs/c.1/strings/0x409
mkdir configs/c.2/strings/0x409echo "0x0525" > idVendor
echo "0xa4a0" > idProductecho "0123456789" > strings/0x409/serialnumber
echo "Samsung Inc." > strings/0x409/manufacturer
echo "Bar Gadget" > strings/0x409/productecho "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.1echo 4100000.udc-controller > UDC

整个过程就是创建了一个 Vendor ID = 0x0525Product ID = 0xa4a0Composite Device,在 Host 侧可以查看这个设备:

$ lsusb-s 1:3
Bus 001 Device 003: ID 0525:a4a0 Netchip Technology, Inc. Linux-USB "Gadget Zero"$ lsusb -v -s 1:3Bus 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 18bDescriptorType 1bcdUSB 2.00bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64idVendor 0x0525 Netchip Technology, Inc.idProduct 0xa4a0 Linux-USB "Gadget Zero"bcdDevice 5.10iManufacturer 1 iProduct 2 iSerial 3 bNumConfigurations 2Configuration Descriptor:bLength 9bDescriptorType 2wTotalLength 0x0045bNumInterfaces 1bConfigurationValue 1iConfiguration 4 bmAttributes 0x80(Bus Powered)MaxPower 120mAInterface Descriptor:bLength 9bDescriptorType 4bInterfaceNumber 0bAlternateSetting 0bNumEndpoints 2bInterfaceClass 255 Vendor Specific ClassbInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor:bLength 7bDescriptorType 5bEndpointAddress 0x81 EP 1 INbmAttributes 2Transfer Type BulkSynch Type NoneUsage Type DatawMaxPacketSize 0x0200 1x 512 bytesbInterval 0Endpoint Descriptor:bLength 7bDescriptorType 5bEndpointAddress 0x01 EP 1 OUTbmAttributes 2Transfer Type BulkSynch Type NoneUsage Type DatawMaxPacketSize 0x0200 1x 512 bytesbInterval 0Interface Descriptor:bLength 9bDescriptorType 4bInterfaceNumber 0bAlternateSetting 1bNumEndpoints 4bInterfaceClass 255 Vendor Specific ClassbInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor:bLength 7bDescriptorType 5bEndpointAddress 0x81 EP 1 INbmAttributes 2Transfer Type BulkSynch Type NoneUsage Type DatawMaxPacketSize 0x0200 1x 512 bytesbInterval 0Endpoint Descriptor:bLength 7bDescriptorType 5bEndpointAddress 0x01 EP 1 OUTbmAttributes 2Transfer Type BulkSynch Type NoneUsage Type DatawMaxPacketSize 0x0200 1x 512 bytesbInterval 0Endpoint Descriptor:bLength 7bDescriptorType 5bEndpointAddress 0x82 EP 2 INbmAttributes 1Transfer Type IsochronousSynch Type NoneUsage Type DatawMaxPacketSize 0x0400 1x 1024 bytesbInterval 4Endpoint Descriptor:bLength 7bDescriptorType 5bEndpointAddress 0x02 EP 2 OUTbmAttributes 1Transfer Type IsochronousSynch Type NoneUsage Type DatawMaxPacketSize 0x0400 1x 1024 bytesbInterval 4Configuration Descriptor:bLength 9bDescriptorType 2wTotalLength 0x0020bNumInterfaces 1bConfigurationValue 2iConfiguration 5 bmAttributes 0x80(Bus Powered)MaxPower 2mAInterface Descriptor:bLength 9bDescriptorType 4bInterfaceNumber 0bAlternateSetting 0bNumEndpoints 2bInterfaceClass 255 Vendor Specific ClassbInterfaceSubClass 0 bInterfaceProtocol 0 iInterface 6 Endpoint Descriptor:bLength 7bDescriptorType 5bEndpointAddress 0x81 EP 1 INbmAttributes 2Transfer Type BulkSynch Type NoneUsage Type DatawMaxPacketSize 0x0200 1x 512 bytesbInterval 0Endpoint Descriptor:bLength 7bDescriptorType 5bEndpointAddress 0x01 EP 1 OUTbmAttributes 2Transfer Type BulkSynch Type NoneUsage Type DatawMaxPacketSize 0x0200 1x 512 bytesbInterval 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:


EndpointTypeDirectionDescript
in_epbulkINSource 发送数据到 Host,注意这数据是 Device 主动生成的
out_epbulkOUTSink 接收 Host 的数据
iso_in_episoINSource 发送数据到 Host
iso_out_episoOUTSink 接收 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 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 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 endpointIN 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 = 0x0525Product 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()

indextypeiterationsvarysglenunalignedtestcasedescript
0nop----“TEST 0: NOP\n”-
1bulkY---“TEST 1: write %d bytes %u times\n”,
param->length, param->iterations
/* Simple non-queued bulk I/O tests */
2bulkY---“TEST 2: read %d bytes %u times\n”,
param->length, param->iterations
-
3bulkYY--“TEST 3: write/%d 0…%d bytes %u times\n”,
param->vary, param->length, param->iterations
-
4bulkYY--“TEST 4: read/%d 0…%d bytes %u times\n”,
param->vary, param->length, param->iterations
-
5bulkY-Y-“TEST 5: write %d sglists %d entries of %d bytes\n”,
param->iterations,param->sglen, param->length
/* Queued bulk I/O tests */
6bulkY-Y-“TEST 6: read %d sglists %d entries of %d bytes\n”,
param->iterations,param->sglen, param->length
-
7bulkYYY-“TEST 7: write/%d %d sglists %d entries 0…%d bytes\n”,
param->vary, param->iterations,param->sglen, param->length
-
8bulkYYY-“TEST 8: read/%d %d sglists %d entries 0…%d bytes\n”,
param->vary, param->iterations,param->sglen, param->length
-
9controlY---“TEST 9: ch9 (subset) control tests, %d times\n”,
param->iterations
/* non-queued sanity tests for control (chapter 9 subset) */
10controlY-Y-“TEST 10: queue %d control calls, %d times\n”,
param->sglen, param->iterations)
/* queued control messaging */
11bulkY---“TEST 11: unlink %d reads of %d\n”,
param->iterations, param->length
/* simple non-queued unlinks (ring with one urb) */
12bulkY---“TEST 12: unlink %d writes of %d\n”,
param->iterations, param->length
-
13controlY---"TEST 13: set/clear %d halts\n"
param->iterations
/* ep halt tests */
14controlYY--“TEST 14: %d ep0out, %d…%d vary %d\n”,
param->iterations,realworld ? 1 : 0, param->length,param->vary
/* control write tests */
15isoY-Y-“TEST 15: write %d iso, %d entries of %d bytes\n”,
param->iterations, param->sglen, param->length
/* iso write tests */
16isoY-Y-“TEST 16: read %d iso, %d entries of %d bytes\n”,
param->iterations, param->sglen, param->length
/* iso read tests */
17bulkY--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 */
18bulkY--Y“TEST 18: read odd addr %d bytes %u times core map\n”,
param->length, param->iterations
-
19bulkY--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 */
20bulkY--Y“TEST 20: read odd addr %d bytes %u times premapped\n”,
param->length, param->iterations
-
21controlYY-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 */
22isoY-YY“TEST 22: write %d iso odd, %d entries of %d bytes\n”,
param->iterations, param->sglen, param->length
/* unaligned iso tests */
23isoY-YY“TEST 23: read %d iso odd, %d entries of %d bytes\n”,
param->iterations, param->sglen, param->length
-
24bulkY-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 */
25intY---“TEST 25: write %d bytes %u times\n”,
param->length, param->iterations
/* Simple non-queued interrupt I/O tests */
26intY---“TEST 26: read %d bytes %u times\n”,
param->length, param->iterations
-
27bulkY-Y-“TEST 27: bulk write %dMbytes\n”,
(param->iterations * param->sglen * param->length) / (1024 * 1024))
/* Performance test */
28bulkY-Y-“TEST 28: bulk read %dMbytes\n”,
(param->iterations * param->sglen * param->length) / (1024 * 1024))
-
29bulkY---“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 zerousb interface device 的文件节点,就可以很方便的调用测试了。

在 USB Testing on Linux 有一个现成的工程,提供了 testusb.c 和 test.sh,但是因为适配的内核比较老,所以需要对 testusb.c 进行一些修改:

- if ((c &#61; open ("/proc/bus/usb/devices", O_RDONLY)) <0) {
&#43; if ((c &#61; 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) !&#61; 0) {
&#43; if (ftw ("/dev/bus/usb", find_testdev, 3) !&#61; 0) {fputs ("ftw failed; is usbfs missing?\n", stderr);return -1;}

简单编译&#xff1a;

gcc -Wall -g -lpthread -o testusb testusb.c

就可以启动测试了&#xff1a;

$ 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 secssudo ./testusb -asudo ./testusb -a -t1 -c1 -s512 -g32 -v32sudo ./testusb -a -t29 -c1 -s512 -g32 -v32// test 10 需要特别注意&#xff0c;容易挂死 host
sudo ./testusb -a -t10 -c1 -s512 -g5 -v32
// test 28 需要特别注意&#xff0c;容易挂死 host
sudo ./testusb -a -t28 -c1 -s512 -g32 -v32

参考资料

1.USB Testing on Linux
2.Linux USB测试
3.linux usb_gadget&#xff1a;设备控制器驱动测试
4.Linux-USB Gadget : Part 5: 测试 PXA UDC 驱动
5.Linux-USB Gadget : Part 4: 最简单的 gadget驱动&#xff1a;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


推荐阅读
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • Ihaveaworkfolderdirectory.我有一个工作文件夹目录。holderDir.glob(*)>holder[ProjectOne, ... [详细]
  • 本文介绍了解决Netty拆包粘包问题的一种方法——使用特殊结束符。在通讯过程中,客户端和服务器协商定义一个特殊的分隔符号,只要没有发送分隔符号,就代表一条数据没有结束。文章还提供了服务端的示例代码。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
author-avatar
长白山天翼张薇_955
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有