当前位置:   article > 正文

vsomeip使用手册-VsomeipUserGuide_vsomeip用户指南

vsomeip用户指南

vsomeip

1.vsomeip概述

vsomeip的代码使用http://some-ip.com/[Scalable service-Oriented MiddlewarE over IP (SOME/IP)] protocol。源码包含:

  • 一个SOME/IP动态库(libvsomeip.so)
  • 还有一个动态库用于SOME/IP的服务发现(libvsomeip-sd.so)。在运行期间如果服务发现功能开启,该动态库就会被加载。

2.构建步骤

2.1构建前准备

  • 能够编译c++11编译器,比如5.2版本及以上的gcc
  • cmake构建工具
  • boost库,版本在1.55及以上
  • 如果使用Google的测试架构,你需要从https://code.google.com/p/googletest/[gtest]下载1.7.0及以上版本
  • 如果想要构建文档,你需要安装asciidoc, source-highlight, doxygen和 graphviz

2.2构建build

你需要进入到vsomeip的根目录:

2.2.1一般构建
#一般构建步骤
mkdir build
cd build
cmake ..
make
  • 1
  • 2
  • 3
  • 4
  • 5
2.2.2自定义路径安装
#如果想要安装在自定义路径(比如 --prefix= ,前提是你需要熟悉autotools。autotools是一些列工具,用于生成makefile),你可以按照如下命令进行cmake
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX:PATH=$YOUR_PATH ..
make
make install
#默认路径会安装到 /usr/local/

#usr 指 Unix System Resource
#/usr:系统级的目录,可以理解为C:/Windows/,/usr/lib理解为C:/Windows/System32。
#/usr/local:用户级的程序目录,可以理解为C:/Progrem Files/。用户自己编译的软件默认会安装到这个目录下。
#/opt:用户级的程序目录,可以理解为D:/Software,opt有可选的意思,这里可以用于放置第三方大型软件(或游戏),当你不需要时,直接rm -rf掉即可。在硬盘容量不够时,也可将/opt单独挂载到其他磁盘上使用。

#源码放哪里?
#/usr/src:系统级的源码目录。
#/usr/local/src:用户级的源码目录

#很多应用都安装在/usr/local下面,那么,这些应用为什么选择这个目录呢?理解了最根源的原因后,也许对你理解linux组织文件的方式有更直观的理解。
#答案是:Automake工具定义了下面的一组变量:
#prefix  /usr/local 
#  exec_prefix   ${prefix}  
#    bindir  ${exec_prefix}/bin  
#    libdir  ${exec_prefix}/lib  
#  includedir    ${prefix}/include
#  datarootdir   ${prefix}/share 
#    datadir ${datarootdir}  
#    mandir  ${datarootdir}/man 
#    infodir ${datarootdir}/info 
#    docdir  ${datarootdir}/doc/${PACKAGE}  

#关于make install命令,可以参考https://zhuanlan.zhihu.com/p/77813702
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
2.2.3添加BasePath
#base path为生成的unix domain socket文件的路径
#可以使用cmake执行命令:
cmake -DBASE_PATH=<YOUR BASE PATH> ..
#默认的base path是/tmp
#对于socket是什么,可以参考https://blog.csdn.net/pashanhu6402/article/details/96428887
  • 1
  • 2
  • 3
  • 4
  • 5
2.2.4使用unicast and/or diagnosis address进行编译
#预定义unicast,unicast是单播地址,默认为127.0.0.1
cmake -DUNICAST_ADDRESS=<YOUR IP ADDRESS> ..
#预定义diagnosis,diagnosis address只占一个字节,默认为0x01
cmake -DDIAGNOSIS_ADDRESS=<YOUR DIAGNOSIS ADDRESS> ..
  • 1
  • 2
  • 3
  • 4
2.2.5使用DEFAULT_CONFIGURATION_FOLDER
#默认使用的配置文件夹所在路径
cmake -DDEFAULT_CONFIGURATION_FOLDER=<DEFAULT CONFIGURATION FOLDER> ..
#默认的default configuration folder路径是/etc/vsomeip,
#但是本电脑实际位置是/usr/local/etc/vsomeip
  • 1
  • 2
  • 3
  • 4
2.2.6使用DEFAULT_CONFIGURATION_FILE
#默认使用的配置文件路径
cmake -DDEFAULT_CONFIGURATION_FILE=<DEFAULT CONFIGURATION FILE> ..
#默认的配置文件是/etc/vsomeip.json
  • 1
  • 2
  • 3
2.2.7使用ENABLE_SIGNAL_HANDLING
#如果没有使用自定义去处理信号,可以使用vsomeip自带的信号处理
cmake -DENABLE_SIGNAL_HANDLING=1 ..
#该选项会通过定义宏VSOMEIP_ENABLE_SIGNAL_HANDLING,来启用vsomeip自己的信号处理代码
#对SIGINT等信号的理解,可以参考https://www.cnblogs.com/alexyuyu/articles/3853583.html
  • 1
  • 2
  • 3
  • 4
2.2.8使用ROUTING_READY_MESSAGE
#可以自定义一些log,当IP路由准备好发送和接收message,可以执行cmake
cmake -DROUTING_READY_MESSAGE=<YOUR MESSAGE> ..
  • 1
  • 2
2.2.9使用ENABLE_CONFIGURATION_OVERLAYS
#To compile vsomeip with configuration overlays enabled
cmake -DENABLE_CONFIGURATION_OVERLAYS=1 ..
  • 1
  • 2
2.2.10使用ENABLE_COMPAT
#To compile vsomeip with enabled vSomeIP 2 compatibility layer
cmake -DENABLE_COMPAT=1 ..
  • 1
  • 2

2.3编译examples

mkdir build
cd build
cmake ..
make examples
  • 1
  • 2
  • 3
  • 4

2.4编译tests

想要编译tests,首先把gtest解压到自定义路径。有一些测试需要在同一个网段中再加一个节点。有两个cmake变量可以用来自动更改json中的ip来适应当前工作的网络配置。

  • TEST_IP_MASTER: test master的ip地址
  • TEST_IP_SLAVE: test slave(另一个节点)的ip地址

任意一个变量没有被设置,那么测试只能在本地运行,无法进行跨物理机的测试。

当然你也可以设置ENABLE_SIGNAL_HANDLING,来使单元测试也能够处理信号。

完整的例子如下:

mkdir build
cd build
export GTEST_ROOT=<the path of googletest>
cmake -DENABLE_SIGNAL_HANDLING=1 -DTEST_IP_MASTER=10.0.3.1 -DTEST_IP_SLAVE=10.0.3.125 ..
  • 1
  • 2
  • 3
  • 4
2.4.1编译check

另有几个make targets可以在test使用

  • make build_tests,只编译tests
  • ctest,在build目录执行该命令可以没有冗余输出的执行tests
  • ctest -V -R $TESTNAME,运行单个测试,相当于ctest --verbose --tests-regex $TESTNAME
  • ctest -N,列出当前可执行的测试

更多有关测试的信息,可以参考tests目录下的readme.txt

还有两个变量(默认值都是OFF)用来控制是否json文件和测试脚本需要拷贝或者连接到build:

  • TEST_SYMLINK_CONFIG_FILES,控制是否json文件和测试脚本需要拷贝到build
  • TEST_SYMLINK_CONFIG_FILES_RELATIVE,控制是否json文件和测试脚本需要连接到build

如果只想编译测试的子集(用于快速的功能检查),可以使用cmake变量TESTS_BAT(默认值是OFF)

2.5编译vsomeip_ctrl

2.6生成文档

想要生成文档就需要按照<> 中描述执行cmake,之后再执行 make doc
这会生成:

  • The README file in html: $BUILDDIR/documentation/README.html
  • A doxygen documentation in $BUILDDIR/documentation/html/index.html

3.启动vsomeip应用和使用环境变量

vsomeip应用启动时以下的环境变量会被读取:

  • VSOMEIP_APPLICATION_NAME,赋予当前程序在vsomeip中使用的名字。vsomeip会通过改名字在配置文件中进行匹配查找。该名字与二进制可执行文件的名字是不一样的。
  • VSOMEIP_CONFIGURATION,vsomeip默认会使用配置文件 /etc/vsomeip.json或者包含配置文件的文件夹/etc/vsomeip。你可以通过该变量使vsomeip使用自定义的配置文件。
  • VSOMEIP_MANDATORY_CONFIGURATION_FILES,vsomeip允许使用mandatory配置文件来加快应用的启动速度(此时,除负责连接某些外部设别的程序之外,其他所有程序运行时都需要按照mandatory配置文件工作)。默认mandatory配置文件是:vsomeip_std.json, vsomeip_app.json和vsomeip_plc.json
  • VSOMEIP_CLIENTSIDELOGGING

注意:

  • 配置文件如果找不到,就会使用默认的配置文件
  • vsomeip会读取${VSOMEIP_CONFIGURATION}中所有的配置文件,但不会读取该路径下的文件夹。

4.配置文件的内容

4.1整体架构

vsomeip的配置文件有多个键值对和键值对数组构成。

一个完整的object,以{开始,以}结束,每一个键值对用:连接,多个键值对用,隔开。如果有array,以[开始,以]结束,多个[]用,隔开。

例如:

{
    "unicast" : "192.168.56.101",
    "logging" :
    {
        "level" : "debug",
        "console" : "true",
        "file" : { "enable" : "false", "path" : "/var/log/vsomeip.log" },
        "dlt" : "false"
    },
    "applications" : 
    [
        {
            "name" : "client-sample",
            "id" : "0x1343"
        },
        {
            "name" : "other-client-sample",
            "id" : "0x1344"
        },
        {
            "name" : "service-sample",
            "id" : "0x1277"
        }            
    ],
    "services" :
    [
        {
            "service" : "0x1234",
            "instance" : "0x5678",
            "reliable" : { "port" : "30509", "enable-magic-cookies" : "false" },
            "unreliable" : "31000"
        },
        {
            "service" : "0x1235",
            "instance" : "0x5678",
            "reliable" : { "port" : "30506", "enable-magic-cookies" : false },
            "unreliable" : "31000"
        }
    ],
    "routing" : "client-sample",
    "service-discovery" :
    {
        "enable" : "true",
        "multicast" : "224.244.224.245",
        "port" : "30490",
        "protocol" : "udp",
        "initial_delay_min" : "10",
        "initial_delay_max" : "100",
        "repetitions_base_delay" : "200",
        "repetitions_max" : "3",
        "ttl" : "3",
        "cyclic_offer_delay" : "2000",
        "request_response_delay" : "1500"
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

4.2基本元素

4.2.1"unicast"

主机的IP地址。

4.2.2"netmask"

主机的子网掩玛。

4.2.3"device"

该参数可选。如果规定了,IP endpoints会绑定到该设备。endpoints应该是服务端和客户端的进行通信的地方。

4.2.4"diagnosis"

长度为一个字节长,用于构建客户端的标识符(即client ID)。如果没有其他规定(例如:自定义了client ID),diagnosis address会被用做client ID的高位字节。

4.2.5"diagnosis_mask"

长度为两个字节。用于控制一个ECU上最大可容纳vsomeip client数量,并规定了client ID的起始值。

例如,默认值0xFF00,表示:高位字节为diagnosis address预留,并且client ID的初始值为自定义的diagnosis address。最大的客户端数量是255,因为 Hamming weight of the inverted mask( Hamming weight:一串符号中非零符号个数。Hamming weight of the inverted mask就是一段字符中值为0的字符个数)是8(2^8-1=255,其中1是留给路由管理的)。生成的client IDs(例如diagnosis address是0x45)会从 0x4501到0x45ff。

当默认值是0xFE00时,clinet ID的数量为511,因为此时 Hamming weight of the inverted mask为9。当diagnosis address是0x45时,client ID的起始值时0x4401(0x4400作为路由器,因为从0x4500开始会超范围),到0x45ff。

4.2.6"network"

用于一个主机上有多个routing managers的情况。该参数可以更改/dev/shm中共享内存段的名字以及/tmp/下的 unix domain sockets名字。

默认情况该参数的值为”vsomeip“,则对应的共享内存被命名为/dev/shm/vsomeip,unix domain sockets被命名为/tmp/vsomeip-$CLIENTID

4.2.7"logging"
4.2.7.1"level"

明确日志的级别,可选的值有六个:trace, debug, info, warning,error, fatal

4.2.7.2"console"

明确log信息是否通过控制台输出,可选的值有:true, false

4.2.7.3"file"

“enable”,决定是否创建一个log文件,可选的值有:true, false

“path”,用于存放生成的日志文件的绝对路径

4.2.7.4"dlt"

决定是否使用Diagnostic Log and Trace (DLT),可选的值有:true, false

4.2.7.5version

vsomeip的版本

4.2.7.5.1’enable’

能否周期的查询vsomeip的版本,可选值有:true(默认值),false

4.2.7.5.2’interval’

周期记录vsomeip版本时的间隔时间,默认是两次记录的间隔为10s

4.2.7.6’memory_log_interval’

routing manager会周期性的记录其使用的内存状况,该参数表示两次记录的时间间隔,单位是秒。当设置参数之比0大时,该参数就会其作用。

4.2.7.7’status_log_interval’

routing manager会周期性的记录其当前状态,该参数表示两次记录的时间间隔,单位是秒。当设置参数之比0大时,该参数就会其作用。

4.3 全部参数配置示例

假设配置文件中使用所有配置参数,那么大概内容为如下所示:

{
    "unicast" : "10.0.2.15",
    "netmask" : "255.255.0.0",
    "device" : "eth0",
    "diagnosis" : "0x01",
    "diagnosis_mask" : "0xFF00",
    "network" : "vsomeip_example",
    "logging" :
    { 
        "level" : "debug",
        "console" : "true",
        "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" },
        "dlt" : "false",
        "version" : {"enable" : "false", "interval" : "20"},
        "memory_log_interval" : "2",
        "status_log_interval" : "2"
    },
    "tracing" : {
        "enable" : "true",
        "sd_enable" : "true",
        "channels" : [
            {
                "name" : "",
                "id" : "0"
            }
        ],
        "filters" : [
            {
                "channel" : "0",
                "matches" : "any",
                "type" : "positive"
            }
        ]
    },
    "applications" : 
    [
        {
            "name" : "service-sample",
            "id" : "0x1277",
            "max_dispatchers" : "12",
            "max_dispatch_time" : "100",
            "threads" : "2",
            "io_thread_nice" : "2",
            "request_debounce_time" : "10",
            "plugins" : [
                {
                    "name" : "",
                    "type" : "application_plugin"
                }
            ],
            "overlay" : "path_other_configuration",
        }
    ],
    "services" :
    [
        {
            "service" : "0x1234",
            "instance" : "0x5678",
            "protocol" :"someip",
            "unicast" : "10.0.2.15",
            "reliable" : {
                "port" : "30490",
                "enable-magic-cookies" : "true",
            },
            "unreliable" : "30509",
            "events" : 
            [
                {
                    "event" : "0x0777",
                    "is_field" : "true",
                    "is_reliable" : "true"
                }
            ],
            "eventgroups" :
            [
                {
                    "eventgroup" : "0x4455",
                    "events" : [ "0x777", "0x778" ],
                    "multicast" : 
                    { 
                        "address" : "224.225.226.233", 
                        "port" : "32344"
                    },
                    "threshold" : 0
                }
            ],
            "debounce-times" : {

            },
            "someip-tp" : {
                "service-to-client" : [

                ],
                "client-to-service" : [

                ]
            }
        }
    ],
    "clients" : [
        {
            "service" : "0x1234",
            "instance" : "0x5678",
            "reliable" : [

            ],
            "unreliable" : [

            ],
            "reliable_remote_ports" : "",
            "unreliable_remote_ports" : "",
            "reliable_client_ports" : "",
            "unreliable_client_ports" : "",
            "first" : "3333",
            "last" : "3335"
        }
    ],
    "payload-sizes" : [
        {
            "unicast" : "10.0.2.15",
            "ports" : {
                "port" : "30490",
                "max-payload-size" : 1000
            }
        }
    ],
    "max-payload-size-local" : 1000,
    "max-payload-size-reliable" : 1000,
    "max-payload-size-unreliable" : 1000,
    "endpoint-queue-limit-external" : 10,
    "endpoint-queue-limit-local" : 10,
    "buffer-shrink-threshold" : 100,
    "tcp-restart-aborts-max" : 10,
    "tcp-connect-time-max" : 10,
    "udp-receive-buffer-size" : 100,
    "internal_services" : [
        {
            "first": {
                "service" : 1111,
                "instance" : "0x5678"
            },
            "last" : {
                "service" : 1111,
                "instance" : "0x5678"
            }
        }
    ],
    "endpoint-queue-limits" : [
        {
            "unicast" : "10.0.2.15",
            "ports" : [
                {
                    "port" : "30490",
                    "queue-size-limit" : 12,
                }
            ]
        }
    ],
    "debounce" : [
        {
            "service" : "0x1234",
            "instance" : "0x5678",
            "events" : [
                {
                    "event" : "0x0777",
                    "on_change" : "true",
                    "ignore" : [
                        {
                            "index" : 1,
                            "mask" : 1
                        }
                    ],
                    "interval" : "20",
                    "on_change_resets_interval_" : "true"
                }
            ]
        }
    ],
    "routing" : "service-sample",
    "routing-credentials" : {
        "uid" : 111,
        "gid" : 111
    },
    "shutdown_timeout" : 5000,
    "warn_fill_level" : 67,
    "service-discovery" :
    {
        "enable" : "true",
        "multicast" : "224.244.224.245",
        "port" : "30490",
        "protocol" : "udp",
        "initial_delay_min" : "10",
        "initial_delay_max" : "100",
        "repetitions_base_delay" : "200",
        "repetitions_max" : "3",
        "ttl" : "3",
        "ttl_factor_offers" : [
            {
                "service" : "0x1234",
                "instance" : "0x5678",
                "ttl_factor" : 1
            }
        ],
        "ttl_factor_subscriptions" : [
            {
                "service" : "0x1234",
                "instance" : "0x5678",
                "ttl_factor" : 1
            }
        ],
        "cyclic_offer_delay" : "2000",
        "request_response_delay" : "1500",
        "offer_debounce_time" : 500
    },
    "watchdog" : {
        "enable" : "true",
        "timeout" : 5000,
        "allowed_missing_pongs" : 3,

    },
    "supports_selective_broadcasts" : [
        {
            "address" : "224.225.226.233"
        }
    ],
    "security" :
    {
        "policies" :
        [
            {
                "credentials" :
                {
                    "uid" : "44",
                    "gid" : "any"
                },
                "allow" :
                [
                    {
                        "requests" :
                        [
                            {
                                "service" : "0x6731",
                                "instance" : "0x0001"
                            }
                        ]
                    }
                ]
            },
            {
                "credentials" :
                {
                    "deny" :
                    [
                        {
                            "uid" : [ "1000", { "first" : "1002", "last" : "max" }],
                            "gid" : [ "0", { "first" : "100", "last" : "243" }, "300"]
                        },
                        {
                            "uid" : ["55"],
                            "gid" : ["55"]
                        }
                    ]
                },
                "allow" :
                [
                    {
                        "offers" :
                        [
                            {
                                "service" : "0x6728",
                                "instances" : [ "0x0001", { "first" : "0x0003", "last" : "0x0007" }, "0x0009"]
                            },
                            {
                                "service" : "0x6729",
                                "instances" : ["0x88"]
                            },
                            {
                                "service" : "0x6730",
                                "instance" : "any"
                            }
                        ],
                        "requests" :
                        [
                            {
                                "service" : "0x6732",
                                "instances" :
                                [
                                    {
                                        "ids" : [ "0x0001", { "first" : "0x0003", "last" : "0x0007" }],
                                        "methods" : [ "0x0001", "0x0003", { "first" : "0x8001", "last" : "0x8006" } ]
                                    },
                                    {
                                        "ids" : [ "0x0009" ],
                                        "methods" : "any"
                                    }
                                ]
                            },
                            {
                                "service" : "0x6733",
                                "instance" : "0x1"
                            },
                            {
                                "service" : "0x6733",
                                "instances" : [ "0x0002", { "first" : "0x0003", "last" : "0x0007" }, "0x0009"]
                            }
                        ]
                    }
                ]
            }
        ]
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/136707?site
推荐阅读
相关标签
  

闽ICP备14008679号