精华内容
下载资源
问答
  • Netty设置option警告Unknown channel option

    万次阅读 热门讨论 2019-05-30 14:34:54
    在设置netty服务端的option时,设置了如下参数。 server.group(boss,worker)//设置时间循环对象,前者用来处理accept事件,后者用于处理已经建立的连接的io //Server是NioServerSocketChannel 客户端是...

    本文使用环境版本是
    netty 4.1.36.Final
    jdk 1.8

    经查,问题的关键点事childOption和option的问题,找了几个答案如下:

    option主要是设置的ServerChannel的一些选项,而childOption主要是设置的ServerChannel的子Channel的选项。 如果是Bootstrap的话,只会有option而没有childOption,所以设置的是客户端Channel的选项。

    option主要是针对boss线程组,child主要是针对worker线程组

    The parameters that we set using ServerBootStrap.option apply to the ChannelConfig of a newly created ServerChannel, i.e., the server socket which listens for and accepts the client connections.
    These options will be set on the Server Channel when bind() or connect() method is called. This channel is one per server.
    And the ServerBootStrap.childOption applies to to a channel’s channelConfig which gets created once the serverChannel accepts a client connection.
    This channel is per client (or per client socket).
    So ServerBootStrap.option parameters apply to the server socket (Server channel) that is listening for connections and ServerBootStrap.
    childOption parameters apply to the socket that gets created once the connection is accepted by the server socket.
    The same can be extended to attr vs childAttr and handler vs childHandler methods in the ServerBootstrap class.
    How could I know which option should be an option and which should be a childOption ?Which ChannelOptions are supported depends on the channel type we are using.
    You can refer to the API docs for the ChannelConfig that you’re using.
    netty.io/4.0/api/io/netty/channel/ChannelConfig.html
    and its sub classes. You should find Available Options section for each ChannelConfig.

    在设置netty服务端的option时,设置了如下参数。

    server.group(boss,worker)//设置时间循环对象,前者用来处理accept事件,后者用于处理已经建立的连接的io
                    //Server是NioServerSocketChannel 客户端是NioSocketChannel绑定了jdk NIO创建的ServerSocketChannel对象,
                    //用它来建立新accept的连接
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG,1024)//
                    // 第2次握手服务端向客户端发送请求确认,同时把此连接放入队列A中,
                    // 然后客户端接受到服务端返回的请求后,再次向服务端发送请求,表示准备完毕,此时服务端收到请求,把这个连接从队列A移动到队列B中,
                    // 此时A+B的总数,不能超过SO_BACKLOG的数值,满了之后无法建立新的TCP连接,2次握手后和3次握手后的总数
                    // 当服务端从队列B中按照FIFO的原则获取到连接并且建立连接[ServerSocket.accept()]后,B中对应的连接会被移除,这样A+B的数值就会变小
                    //此参数对于程序的连接数没影响,会影响正在准备建立连接的握手。
                    .option(ChannelOption.SO_KEEPALIVE,true)
                    //启用心跳,双方TCP套接字建立连接后(即都进入ESTABLISHED状态),
                    // 并且在两个小时左右上层没有任何数据传输的情况下,这套机制才会被激活,TCP会自动发送一个活动探测数据报文
                    .option(ChannelOption.TCP_NODELAY,true)
                    //TCP协议中,TCP总是希望每次发送的数据足够大,避免网络中充满了小数据块。
                    // Nagle算法就是为了尽可能的发送大数据快。
                    // TCP_NODELAY就是控制是否启用Nagle算法。
                    // 如果要求高实时性,有数据发送时就马上发送,就将该选项设置为true关闭Nagle算法;
                    // 如果要减少发送次数减少网络交互,就设置为false等累积一定大小后再发送。默认为false。
                    .option(ChannelOption.SO_REUSEADDR,true)//是否允许重复绑定端口,重复启动,会把端口从上一个使用者上抢过来
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS,30000)//连接超时30000毫秒
                    .option(ChannelOption.SO_TIMEOUT,5000)//输入流的read方法被阻塞时,接受数据的等待超时时间5000毫秒,抛出SocketException
                    //child是在客户端连接connect之后处理的handler,不带child的是在客户端初始化时需要进行处理的
                    .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)//缓冲池
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast("decoder",new DotDecodeHandler());
                        }
                    });
    

    在启动的时候除了警告如下

    五月 30, 2019 10:38:41 上午 io.netty.bootstrap.AbstractBootstrap setChannelOption
    警告: Unknown channel option 'SO_KEEPALIVE' for channel '[id: 0x3372ab6d]'
    五月 30, 2019 10:38:41 上午 io.netty.bootstrap.AbstractBootstrap setChannelOption
    警告: Unknown channel option 'TCP_NODELAY' for channel '[id: 0x3372ab6d]'
    五月 30, 2019 10:38:41 上午 io.netty.bootstrap.AbstractBootstrap setChannelOption
    警告: Unknown channel option 'SO_TIMEOUT' for channel '[id: 0x3372ab6d]'
    

    经过跟踪调试发现点在于NETTY版本问题。
    在setOption的时候,首先会判断JDK版本,然后根据1.7为分界线,去set。
    在从NioOption中查找key-value对,如果没有找到,就会去JDK的Option中去查找,如果仍然没找到,那么就会报出警告。如下:

    io.netty.bootstrap. AbstractBootstrap

        private static void setChannelOption(Channel channel, ChannelOption<?> option, Object value, InternalLogger logger) {
            try {
                if (!channel.config().setOption(option, value)) {
                    logger.warn("Unknown channel option '{}' for channel '{}'", option, channel);
                }
            } catch (Throwable var5) {
                logger.warn("Failed to set channel option '{}' with value '{}' for channel '{}'", new Object[]{option, value, channel, var5});
            }
    
        }
    
    

    io.netty.channel.socket.nio. NioServerSocketChannel

            public <T> boolean setOption(ChannelOption<T> option, T value) {
            //此处根据jdk版本去执行不同的set方法
                return PlatformDependent.javaVersion() >= 7 && option instanceof NioChannelOption ? NioChannelOption.setOption(this.jdkChannel(), (NioChannelOption)option, value) : super.setOption(option, value);
            }
    

    io.netty.channel.socket. DefaultServerSocketChannelConfig

        public <T> boolean setOption(ChannelOption<T> option, T value) {
            this.validate(option, value);
            if (option == ChannelOption.SO_RCVBUF) {
                this.setReceiveBufferSize((Integer)value);
            } else if (option == ChannelOption.SO_REUSEADDR) {
                this.setReuseAddress((Boolean)value);
            } else {
                if (option != ChannelOption.SO_BACKLOG) {
                    return super.setOption(option, value); //如果没有找到,去父类找
                }
    
                this.setBacklog((Integer)value);
            }
    
            return true;
        }
    
    

    io.netty.channel. DefaultChannelConfig

    public <T> boolean setOption(ChannelOption<T> option, T value) {
            this.validate(option, value);
            //在此处没有找到我设置的SO_KEEPALIVE/TCP_NODELAY/SO_TIMEOUT
            if (option == ChannelOption.CONNECT_TIMEOUT_MILLIS) {
                this.setConnectTimeoutMillis((Integer)value);
            } else if (option == ChannelOption.MAX_MESSAGES_PER_READ) {
                this.setMaxMessagesPerRead((Integer)value);
            } else if (option == ChannelOption.WRITE_SPIN_COUNT) {
                this.setWriteSpinCount((Integer)value);
            } else if (option == ChannelOption.ALLOCATOR) {
                this.setAllocator((ByteBufAllocator)value);
            } else if (option == ChannelOption.RCVBUF_ALLOCATOR) {
                this.setRecvByteBufAllocator((RecvByteBufAllocator)value);
            } else if (option == ChannelOption.AUTO_READ) {
                this.setAutoRead((Boolean)value);
            } else if (option == ChannelOption.AUTO_CLOSE) {
                this.setAutoClose((Boolean)value);
            } else if (option == ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK) {
                this.setWriteBufferHighWaterMark((Integer)value);
            } else if (option == ChannelOption.WRITE_BUFFER_LOW_WATER_MARK) {
                this.setWriteBufferLowWaterMark((Integer)value);
            } else if (option == ChannelOption.WRITE_BUFFER_WATER_MARK) {
                this.setWriteBufferWaterMark((WriteBufferWaterMark)value);
            } else if (option == ChannelOption.MESSAGE_SIZE_ESTIMATOR) {
                this.setMessageSizeEstimator((MessageSizeEstimator)value);
            } else {
                if (option != ChannelOption.SINGLE_EVENTEXECUTOR_PER_GROUP) {
                	//如果都没有找到则返回false,层层抛出,在log处打印出警告
                    return false;
                }
    
                this.setPinEventExecutorPerGroup((Boolean)value);
            }
    
            return true;
        }
    

    然后我使用低版本的netty(小于等于 4.1.7.Final ),不会报出警告,而且在处理setOption的时候有不同:

    io.netty.bootstrap. AbstractBootstrap

        final ChannelFuture initAndRegister() {
            Channel channel = null;
    
            try {
                channel = this.channelFactory.newChannel();
                //此处初始化channel
                this.init(channel);
            } catch (Throwable var3) {
                if (channel != null) {
                    channel.unsafe().closeForcibly();
                }
    
                return (new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE)).setFailure(var3);
            }
    
            ChannelFuture regFuture = this.config().group().register(channel);
            if (regFuture.cause() != null) {
                if (channel.isRegistered()) {
                    channel.close();
                } else {
                    channel.unsafe().closeForcibly();
                }
            }
    
            return regFuture;
        }
    
    

    io.netty.bootstrap. ServerBootstrap

        void init(Channel channel) throws Exception {
            Map<ChannelOption<?>, Object> options = this.options0();
            synchronized(options) {
            	//开始设置option
                channel.config().setOptions(options);
            }
    
            Map<AttributeKey<?>, Object> attrs = this.attrs0();
            synchronized(attrs) {
                Iterator i$ = attrs.entrySet().iterator();
    
                while(true) {
                    if (!i$.hasNext()) {
                        break;
                    }
    
                    Entry<AttributeKey<?>, Object> e = (Entry)i$.next();
                    AttributeKey<Object> key = (AttributeKey)e.getKey();
                    channel.attr(key).set(e.getValue());
                }
            }
    
            ChannelPipeline p = channel.pipeline();
            final EventLoopGroup currentChildGroup = this.childGroup;
            final ChannelHandler currentChildHandler = this.childHandler;
            final Entry[] currentChildOptions;
            synchronized(this.childOptions) {
                currentChildOptions = (Entry[])this.childOptions.entrySet().toArray(newOptionArray(this.childOptions.size()));
            }
    
            final Entry[] currentChildAttrs;
            synchronized(this.childAttrs) {
                currentChildAttrs = (Entry[])this.childAttrs.entrySet().toArray(newAttrArray(this.childAttrs.size()));
            }
    
            p.addLast(new ChannelHandler[]{new ChannelInitializer<Channel>() {
                public void initChannel(Channel ch) throws Exception {
                    final ChannelPipeline pipeline = ch.pipeline();
                    ChannelHandler handler = ServerBootstrap.this.config.handler();
                    if (handler != null) {
                        pipeline.addLast(new ChannelHandler[]{handler});
                    }
    
                    ch.eventLoop().execute(new Runnable() {
                        public void run() {
                            pipeline.addLast(new ChannelHandler[]{new ServerBootstrap.ServerBootstrapAcceptor(currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs)});
                        }
                    });
                }
            }});
        }
    
    

    io.netty.channel. DefaultChannelConfig

        public boolean setOptions(Map<ChannelOption<?>, ?> options) {
            if (options == null) {
                throw new NullPointerException("options");
            } else {
                boolean setAllOptions = true;
                Iterator i$ = options.entrySet().iterator();
    
                while(i$.hasNext()) {
                    Entry<ChannelOption<?>, ?> e = (Entry)i$.next();
                    //此处循环set,如果this.setOption返回false,那么setAllOptions就是false,接下来我们进入this.setOption
                    if (!this.setOption((ChannelOption)e.getKey(), e.getValue())) {
                        setAllOptions = false;
                    }
                }
    
                return setAllOptions;
            }
        }
    
    

    io.netty.channel.socket. DefaultServerSocketChannelConfig

        public <T> boolean setOption(ChannelOption<T> option, T value) {
            this.validate(option, value);
            if (option == ChannelOption.SO_RCVBUF) {
                this.setReceiveBufferSize((Integer)value);
            } else if (option == ChannelOption.SO_REUSEADDR) {
                this.setReuseAddress((Boolean)value);
            } else {
                if (option != ChannelOption.SO_BACKLOG) {
               		//此处找到不到SO_KEEPALIVE等参数后,会向上从父类中查询
                    return super.setOption(option, value);
                }
    
                this.setBacklog((Integer)value);
            }
    
            return true;
        }
    
    

    io.netty.channel. DefaultChannelConfig
    发现也没有SO_KEEPALIVE选项,返回false
    但是在返回后,没有地方记录这个false,而且也没有地方打印log

        public <T> boolean setOption(ChannelOption<T> option, T value) {
            this.validate(option, value);
            if (option == ChannelOption.CONNECT_TIMEOUT_MILLIS) {
                this.setConnectTimeoutMillis((Integer)value);
            } else if (option == ChannelOption.MAX_MESSAGES_PER_READ) {
                this.setMaxMessagesPerRead((Integer)value);
            } else if (option == ChannelOption.WRITE_SPIN_COUNT) {
                this.setWriteSpinCount((Integer)value);
            } else if (option == ChannelOption.ALLOCATOR) {
                this.setAllocator((ByteBufAllocator)value);
            } else if (option == ChannelOption.RCVBUF_ALLOCATOR) {
                this.setRecvByteBufAllocator((RecvByteBufAllocator)value);
            } else if (option == ChannelOption.AUTO_READ) {
                this.setAutoRead((Boolean)value);
            } else if (option == ChannelOption.AUTO_CLOSE) {
                this.setAutoClose((Boolean)value);
            } else if (option == ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK) {
                this.setWriteBufferHighWaterMark((Integer)value);
            } else if (option == ChannelOption.WRITE_BUFFER_LOW_WATER_MARK) {
                this.setWriteBufferLowWaterMark((Integer)value);
            } else if (option == ChannelOption.WRITE_BUFFER_WATER_MARK) {
                this.setWriteBufferWaterMark((WriteBufferWaterMark)value);
            } else if (option == ChannelOption.MESSAGE_SIZE_ESTIMATOR) {
                this.setMessageSizeEstimator((MessageSizeEstimator)value);
            } else {
                if (option != ChannelOption.SINGLE_EVENTEXECUTOR_PER_GROUP) {
                    return false;
                }
    
                this.setPinEventExecutorPerGroup((Boolean)value);
            }
    
            return true;
        }
    
    
    展开全文
  • Option 43 的配置

    千次阅读 2020-06-26 08:49:47
    为使AP能够正常识别Option 43属性的内容,Option 43属性需要按照一定的规则来填写:比如AC的IP地址为192.168.22.1时,需要填写的值为 030C3139322E3136382E32322E31。其中,03为固定值,代表Option 43的子选项类 型...

    Microsoft DHCP Server

    一、Microsoft DHCP Server 中 Option 43 选项的填写规则
    为使AP能够正常识别Option 43属性的内容,Option 43属性需要按照一定的规则来填写:比如AC的IP地址为192.168.22.1时,需要填写的值为 030C3139322E3136382E32322E31。其中,03为固定值,代表Option 43的子选项类 型;十六进制数0C(“0C”等于十进制数“12”)代表AC的IP地址192.168.22.1的 长度,包含小数点“.”;十六进制数31对应字符“1”的ASCII值,32对应字符 “2”的ASCII值,依此类推,十六进制2E对应字符小数点“.”的ASCII值,即值 3139322E3136382E32322E31表示AC的IP地址192.168.22.1。另外,对于涉及到多个AC,Option 43要填写多个IP地址的情形(比如AC 双链路备 份组网等),IP地址之间以逗号“,”间隔,逗号“,”对应的ASCII值为2C,如主备 AC的IP地址分别为:192.168.100.2,192.168.100.3,那Option 43属性应该填写为: 031B3139322E3136382E3130302E322C3139322E3136382E3130302E33 。其中,03为固定值,代表Option 43的子选项类型;十六进制1B(“1B”等于十进制数“27”) 表示两个IP地址字符的个数,包含中间间隔的逗号“,”和小数点“.”,十六进制 数31对应字符“1”的ASCII值,32对应字符“2”的ASCII值,依此类推。十六进制 数2E对应字符小数点“.”的ASCII值,十六进制2C对应字符逗号“,”的ASCII 值,即值3139322E3136382E3130302E322C3139322E3136382E3130302E33表示AC 的IP地址192.168.100.2,192.168.100.3。
    二、配置步骤打开Windows server 2003的DHCP Server选项,右键点击“服务器选项”,打开 “配置选项”。在打开的“服务器选项”窗口中勾选“043 供应商特定信息”,如下图:在打开的“服务器选项”窗口下边“二进制”一栏中填入AC的地址,填写的规则 参考Microsoft DHCP Server中Option 43选项的填写规则。例如,AC的地址为 192.168.22.1,需要填写的值为030C3139322E3136382E32322E31

    Linux DHCP Server

    一、Linux DHCP Server 中 Option 43 选项的写规则
    在Liunx系统的DHCP服务器中配置Option 43,Option 43字段要按照十六进制ASCII来填 写,并且用冒号“:”隔开。以AC的IP地址为192.168.22.1为例,对应的Option 43字段应该填写为:03:0C: 31:39:32:2E:31:36:38:2E:32:32:2E:31。其中,03为固定值,代表子选项类型;十六 进制数0C(“0C”等于十进制数“12”)代表IP地址192.168.22.1的长度,包含小数 点“.”;十六进制数31对应“1”的ACCII值,32对应“2”的ASCII值,以此类 推,十六进制数2E对应小数点“.”的ASCII值,即值31:39:32:2E:31:36:38:2E: 32:32:2E:31表示AC的IP地址192.168.22.1。 对于涉及到多个AC,Option要填写多个IP地址的情形,IP地址要以逗号“,”间 隔,逗号“,”对应的ASCII值为2C。比如两个AC的IP地址分别为192.168.100.2和 192.168.100.3,则对应的Option 43字段为03:1B:31:39:32:2E:31:36:38:2E:31:30:30:2E:32:2C:31:39:32:2E:31:36:38:2E:31:30:30:2E:33。其中,03为固定值,代表子选项类型;十六进制数1B(“1B”等于十进制数“27”)代表两个IP地址的长 度,包含小数点“.”和逗号“,”;十六进制数31对应“1”的ACCII值,32对应 “2”的ASCII值,以此类推,十六进制数2E对应小数点“.”的ASCII值,十六进制 数2C对应逗号“,”的ASCII值,即值31:39:32:2E:31:36:38:2E:31:30:30:2E:32:2C: 31:39:32:2E:31:36:38:2E:31:30:30:2E:33表述AC的IP地址192.168.100.2,192.168.100.3。
    二、配置步骤

    1. 登录Linux系统并安装DHCP Server。# 安装DHCP Server。yast -i dhcp dhcp-server# 进入/etc/sysconfig目录下打开dhcpd文件,修改配置,设置DHCP Interface为端口 eth0。DHCP_INTERFACE = “eth0” DHCPD_RUN_CHROOTED = “yes”
    2. 配置地址池,使其可以为AP分配IP地址,同时配置Option 43,使AP能够获得AC的IP 地址。假定AP的地址为192.168.100.0/24,网关为192.168.100.1,AC的地址为 192.168.22.1。# 进入/etc目录,打开dhcpd.conf文件,进行如下配置。option serverip code 43 = string;subnet 192.168.100.0 netmask 255.255.255.0 {range 192.168.100.2 192.168.100.254;option routers 192.168.100.1;option subnet-mask 255.255.255.0;option serverip 03:0C:31:39:32:2E:31:36:38:2E:32:32:2E:31;}

    HuaWei OS DHCP Server

    一、Huawei OS DHCP Server 中 Option 43 选项的填写规则
    当Huawei设备,如交换机、路由器、AC等作为DHCP服务器时,同样需要配置Option 43。在Microsoft DHCP Server上的Option 43字段填写规则同样适用于Huawei设备,参考 Microsoft DHCP Server中Option 43选项的填写规则。另外,在Huawei设备的命令行配置 视图中,还可以采用下面的规则来进行Option 43的配置:同样以AC的IP地址为192.168.22.1为例,配置命令为option 43 sub-option 3 hex 3139322E3136382E32322E31或者命令option 43 sub-option 3 ascii 192.168.22.1。其中,sub-option 3为固定值,代表子选项类型;hex 3139322E3136382E32322E31与ascii 192.168.22.1分别是AC地址192.168.22.1的HEX格式和ASCII格式。对于涉及到多个AC,Option要填写多个IP地址的情形,IP地址同样要以“,”间 隔,逗号“,”对应的ASCII值为2C。比如两个AC的IP地址分别为192.168.22.1和 192.168.22.2,则DHCP服务器上的配置命令为option 43 sub-option 3 hex 3139322E3136382E3130302E322C3139322E3136382E3130302E33或者option 43 sub-option 3 ascii 192.168.22.1,192.168.22.2。
    二、配置步骤当Huawei设备的DHCP服务器地址池为全局地址池时,执行下列步骤:连接Huawei设备并进入命令配置视图;使能DHCP Server功能,并配置地址池,使其可以为AP分配IP地址。 systerm-view[Quidway] dhcp enable [Quidway] ip pool huawei[Quidway-ip-pool-huawei] network 192.168.100.0 255.255.255.0[Quidway-ip-pool-huawei] gateway-list 192.168.100.1 配置Option 43,使AP能够获得AC的IP地址。假设AC的IP地址为10.10.10.1。[Quidway-ip-pool-huawei] option 43 sub-option 3 hex 31302E31302E31302E31说明:还可以执行命令option 43 hex 030A31302E31302E31302E31或者option 43 sub-option 3 ascii 10.10.10.1来完成Option 43的配置。

    转载于:https://blog.51cto.com/77jiayuan/1950843

    展开全文
  • Hook 方法之 pytest_addoption: pytest_addoption可以让用户注册一个自定义的命令行参数,方便用户将数据传递给pytest; 这个 Hook方法一般和内置fixturepytestconfig配合使用,pytest_addoption注册命令行参数...

    Hook 方法之 pytest_addoption :

    pytest_addoption 可以让用户注册一个自定义的命令行参数,方便用户将数据传递给 pytest;

    这个 Hook 方法一般和 内置 fixture pytestconfig 配合使用,pytest_addoption 注册命令行参数,pytestconfig 通过配置对象读取参数的值;

     pytest_addoption 注册、pytestconfig 获取命令行参数 :

    # conftest.py
     
    import pytest
     
    # 注册自定义参数 cmdopt 到配置对象
    def pytest_addoption(parser):
        parser.addoption("--cmdopt", action="store",
                         default="None",
                         help="将自定义命令行参数 ’--cmdopt' 添加到 pytest 配置中")
     
    # 从配置对象获取 cmdopt 的值
    @pytest.fixture(scope='session')
    def cmdopt(pytestconfig):
        return pytestconfig.getoption('--cmdopt')
     
    # 然后任何 fixture 或测试用例都可以调用 cmdopt 来获得设备信息

    parser.addoption() 参数说明:

    1. name:自定义命令行参数的名字,可以是:"foo", "-foo" 或 "--foo";
    2. action:在命令行中遇到此参数时要采取的基本操作类型;
    3. nargs:应该使用的命令行参数的数量;
    4. const:某些操作和nargs选择所需的常量值;
    5. default:如果参数不在命令行中,则生成的默认值。
    6. type:命令行参数应该转换为的类型;
    7. choices:参数允许值的容器;
    8. required:命令行选项是否可以省略(仅可选);
    9. help:对参数作用的简要说明;
    10. metavar:用法消息中参数的名称;
    11. dest:要添加到 parse_args() 返回的对象中的属性的名称;

    挑几个比较常用的来演示:

    1. name:这个不用多说,自定义的参数的名字;

    2. action 、default 和 const、help

    action="store":默认,只存储参数的值,可以存储任何类型的值,此时 default 也可以是任何类型的值,而且命令行参数多次使用也只能生效一个,最后一个值覆盖之前的值;

    # 注册自定义参数 cmdopt 到配置对象
    def pytest_addoption(parser):
        parser.addoption("--cmdopt", action="store",
                         default="这个是默认值...",
                         help="将命令行参数 ’--cmdopt' 添加到 pytest 配置中")
    
    # 从配置对象中读取自定义参数的值
    @pytest.fixture(scope="session")
    def cmdopt(request):
        return request.config.getoption("--cmdopt")
    
    # 将自定义参数的值打印出来
    @pytest.fixture(autouse=True)
    def fix_1(cmdopt):
        print('\n --cmdopt的值:',cmdopt)
    
    if __name__ == '__main__':
        # 使用参数
        pytest.main(['-s', '--cmdopt=98k'])
    # 控制台打印参数值:
    ============================= test session starts =============================
    test_Z.py::TestDemoA::test_A_001 
     --cmdopt的值: 98k
    PASS
    ============================== 1 passed in 0.02s ==============================

    action="append":存储一个列表,用 append 模式 将可以同时多次使用自定义参数,并且 default  默认值必须是一个列表,pytest 会把 default  默认参数的值和多个自定义参数的值放在一个列表中:

    # 注册自定义参数 cmdopt 到配置对象
    def pytest_addoption(parser):
        parser.addoption("--cmdopt", action="append",
                         default=['这是默认参数'],
                         help="将命令行参数 ’--cmdopt' 添加到 pytest 配置中")
    
    if __name__ == '__main__':
        # 使用参数
        pytest.main(['-s', '--cmdopt=98k', '--cmdopt=毛瑟小手枪'])
    # 控制台打印参数值:
    ============================= test session starts =============================
    test_Z.py::TestDemoA::test_A_001 
     --cmdopt的值: ['这是默认参数', '98k', '毛瑟小手枪']
    PASS
    ============================== 1 passed in 0.02s ==============================

    action="store_const":使用 const 为命令行参数指定一个常量值,必须和 const 参数同时使用,使用这个模式后命令行参数不能赋值:

    def pytest_addoption(parser):
        parser.addoption("--cmdopt", action="store_const",
                         default='这是默认参数',
                         const='这个是为命令行参数指定的常量值...',
                         help="将命令行参数 ’--cmdopt' 添加到 pytest 配置中")
    
    if __name__ == '__main__':
        pytest.main(['-s','--cmdopt'])
    # 控制台打印参数值:
    ============================= test session starts =============================
    test_Z.py::TestDemoA::test_A_001 
     --cmdopt的值: 这个是为命令行参数指定的常量值...
    PASS
    ============================== 1 passed in 0.02s ==============================

    action="append_const":存储一个列表,使用 const 为命令行参数指定一个常量值,并将 default 默认值和 const  常量值添加到列表中,这个模式可以同时多次使用自定义参数,但是还是不能赋值,只能使用常量;

    def pytest_addoption(parser):
        parser.addoption("--cmdopt", action="append_const",
                         default=['这是默认参数'],
                         const='这个是为命令行参数指定的常量值...',
                         help="将命令行参数 ’--cmdopt' 添加到 pytest 配置中")
    
    if __name__ == '__main__':
        pytest.main(['-s','--cmdopt', '--cmdopt'])
    # 控制台打印参数值:
    ============================= test session starts =============================
    test_Z.py::TestDemoA::test_A_001 
     --cmdopt的值: ['这是默认参数', '这个是为命令行参数指定的常量值...', '这个是为命令行参数指定的常量值...']
    PASS
    ============================== 1 passed in 0.02s ==============================

    3. type:type 的类型可以是 python 的基础类型,比如:int,str,float,list 等类型,如果不指定类型的话,pytest会把接受到的参数值都默认为 str 类型,所以我们有时需要指定参数的类型:

    注意:在使用 type 指定类型时,也需要把 default 的类型修改为同样的类型!

    def pytest_addoption(parser):
        parser.addoption("--cmdopt", action="store",
                         default=100,
                         type=int,
                         help="将命令行参数 ’--cmdopt' 添加到 pytest 配置中")
    
    if __name__ == '__main__':
        pytest.main(['-s', f'--cmdopt=888'])
    # 控制台打印参数值:
    ============================= test session starts =============================
    --cmdopt的值: 888
    --cmdopt的类型: <class 'int'>
    PASS
    ============================== 1 passed in 0.02s ==============================

    4. choices:choices 可以指定几个值,自定义参数必须在这几个值中选择一个,否则会报错:

    def pytest_addoption(parser):
        parser.addoption("--cmdopt", action="store",
                         default='100',
                         choices= ['python', 'java', 'c++'],
                         help="将命令行参数 ’--cmdopt' 添加到 pytest 配置中")
    
    if __name__ == '__main__':
        pytest.main(['-s', f'--cmdopt=888'])
    # 控制台打印结果:
    
    ERROR: usage: conftest.py [options] [file_or_dir] [file_or_dir] [...]
    conftest.py: error: argument --cmdopt: invalid choice: '888' (choose from 'python', 'java', 'c++')

     

    展开全文
  • netty系列之ChannelOption

    千次阅读 2019-07-04 22:09:18
    在netty 启动的时候会设置相关的ChannelOption, 无论是在ServerBootstrap还是在Bootstrap, 接下来解释一下常用的ChannelOption 2、常用ChannelOption ChannelOption.SO_BACKLOG (一般用于option–>boss) ...

    1、概述

    在netty 启动的时候会设置相关的ChannelOption, 无论是在ServerBootstrap还是在Bootstrap,
    接下来解释一下常用的ChannelOption

    2、常用ChannelOption

    • ChannelOption.SO_BACKLOG (一般用于option–>boss)
      BACKLOG用于构造服务端套接字ServerSocket对象,标识当服务器请求处理线程都处于工作是(用完了),用于临时存放已完成三次握手的请求的队列的最大长度。如果未设置或所设置的值小于1,Java将使用默认值50。

    • ChannelOption.SO_REUSEADDR (一般用于option–>boss)
      SO_REUSEADDR 对应的是socket选项中SO_REUSEADDR,这个参数表示允许重复使用本地地址和端口,例如,某个服务占用了TCP的8080端口,其他服务再对这个端口进行监听就会报错,SO_REUSEADDR这个参数就是用来解决这个问题的,该参数允许服务公用一个端口,这个在服务器程序中比较常用,例如某个进程非正常退出,对一个端口的占用可能不会立即释放,这时候如果不设置这个参数,其他进程就不能立即使用这个端口。

    • ChannelOption.ALLOCATOR
      Netty参数,ByteBuf的分配器(重用缓冲区),默认值为ByteBufAllocator.DEFAULT,4.0版本为UnpooledByteBufAllocator,4.1版本为PooledByteBufAllocator。该值也可以使用系统参数io.netty.allocator.type配置,使用字符串值:“unpooled”,“pooled”。
      额外解释, Netty4.1使用对象池,重用缓冲区(可以直接只用这个配置)
      bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
      bootstrap.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);

    • ChannelOption.RCVBUF_ALLOCATOR (一般用于option->boss)
      Netty参数,用于Channel分配接受Buffer的分配器,默认值为AdaptiveRecvByteBufAllocator.DEFAULT,是一个自适应的接受缓冲区分配器,能根据接受到的数据自动调节大小。可选值为FixedRecvByteBufAllocator,固定大小的接受缓冲区分配器。

    • ChannelOption.TCP_NODELAY (一般用于childOption)
      TCP_NODELAY 对应于socket选项中的TCP_NODELAY,该参数的使用和Nagle算法有关,Nagle算法是将小的数据包组装为更大的帧进行发送,而不会来一个数据包发送一次,目的是为了提高每次发送的效率,因此在数据包没有组成足够大的帧时,就会延迟该数据包的发送,虽然提高了网络负载却造成了延时,TCP_NODELAY参数设置为true,就可以禁用Nagle算法,即使用小数据包即时传输。
      或者
      TCP_NODELAY就是用于启用或关闭Nagle算法。如果要求高实时性,有数据发送时就马上发送,就将该选项设置为true关闭Nagle算法;如果要减少发送次数减少网络交互,就设置为false等累积一定大小后再发送。默认为false。

    • ChannelOption.SO_SNDBUF 和ChannelOption.SO_RCVBUF (一般用于childOption)
      SO_SNDBUF 和 SO_RCVBUF对应socket中的SO_SNDBUF和SO_RCVBUF参数,即设置发送缓冲区和接收缓冲区的大小,发送缓冲区用于保存发送数据,直到发送成功,接收缓冲区用于保存网络协议站内收到的数据,直到程序读取成功。
      或者
      SO_RCVBUF参数,TCP数据接收缓冲区大小。该缓冲区即TCP接收滑动窗口,linux操作系统可使用命令:cat /proc/sys/net/ipv4/tcp_rmem查询其大小。一般情况下,该值可由用户在任意时刻设置,但当设置值超过64KB时,需要在连接到远端之前设置。
      SO_SNDBUF参数,TCP数据发送缓冲区大小。该缓冲区即TCP发送滑动窗口,linux操作系统可使用命令:cat /proc/sys/net/ipv4/tcp_smem查询其大小。

    • ChannelOption.CONNECT_TIMEOUT_MILLIS: (一般用于Bootstrap或者childOption)
      Netty参数,连接超时毫秒数,默认值30000毫秒即30秒。

    • ChannelOption.SO_LINGER (一般用于childOption)
      Socket参数,关闭Socket的延迟时间,默认值为-1,表示禁用该功能。-1表示socket.close()方法立即返回,但OS底层会将发送缓冲区全部发送到对端。0表示socket.close()方法立即返回,OS放弃发送缓冲区的数据直接向对端发送RST包,对端收到复位错误。非0整数值表示调用socket.close()方法的线程被阻塞直到延迟时间到或发送缓冲区中的数据发送完毕,若超时,则对端会收到复位错误。

    • ChannelOption.SO_KEEPALIVE
        Socket参数,连接保活,默认值为False。启用该功能时,TCP会主动探测空闲连接的有效性。可以将此功能视为TCP的心跳机制,需要注意的是:默认的心跳间隔是7200s即2小时。Netty默认关闭该功能。

    • ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK (一般用于childOption)
        Netty参数,写高水位标记,默认值64KB。如果Netty的写缓冲区中的字节超过该值,Channel的isWritable()返回False。

    • ChannelOption.WRITE_BUFFER_LOW_WATER_MARK (一般用于childOption)
        Netty参数,写低水位标记,默认值32KB。当Netty的写缓冲区中的字节超过高水位之后若下降到低水位,则Channel的isWritable()返回True。写高低水位标记使用户可以控制写入数据速度,从而实现流量控制。推荐做法是:每次调用channl.write(msg)方法首先调用channel.isWritable()判断是否可写。

    • ChannelOption.AUTO_READ (一般用于childOption)
        Netty参数,自动读取,默认值为True。Netty只在必要的时候才设置关心相应的I/O事件。对于读操作,需要调用channel.read()设置关心的I/O事件为OP_READ,这样若有数据到达才能读取以供用户处理。该值为True时,每次读操作完毕后会自动调用channel.read(),从而有数据到达便能读取;否则,需要用户手动调用channel.read()。需要注意的是:当调用config.setAutoRead(boolean)方法时,如果状态由false变为true,将会调用channel.read()方法读取数据;由true变为false,将调用config.autoReadCleared()方法终止数据读取。

    • ChannelOption.MAX_MESSAGES_PER_READ
        Netty参数,一次Loop读取的最大消息数,对于ServerChannel或者NioByteChannel,默认值为16,其他Channel默认值为1。默认值这样设置,是因为:ServerChannel需要接受足够多的连接,保证大吞吐量,NioByteChannel可以减少不必要的系统调用select。

    • ChannelOption.WRITE_SPIN_COUNT
        Netty参数,一个Loop写操作执行的最大次数,默认值为16。也就是说,对于大数据量的写操作至多进行16次,如果16次仍没有全部写完数据,此时会提交一个新的写任务给EventLoop,任务将在下次调度继续执行。这样,其他的写请求才能被响应不会因为单个大数据量写请求而耽误。

    • ChannelOption.MESSAGE_SIZE_ESTIMATOR
        Netty参数,消息大小估算器,默认为DefaultMessageSizeEstimator.DEFAULT。估算ByteBuf、ByteBufHolder和FileRegion的大小,其中ByteBuf和ByteBufHolder为实际大小,FileRegion估算值为0。该值估算的字节数在计算水位时使用,FileRegion为0可知FileRegion不影响高低水位

    • ChannelOption.SINGLE_EVENTEXECUTOR_PER_GROUP
        Netty参数,单线程执行ChannelPipeline中的事件,默认值为True。该值控制执行ChannelPipeline中执行ChannelHandler的线程。如果为True,整个pipeline由一个线程执行,这样不需要进行线程切换以及线程同步,是Netty4的推荐做法;如果为False,ChannelHandler中的处理过程会由Group中的不同线程执行。






    参考地址:

    https://blog.csdn.net/mastershaw/article/details/79723214
    http://blog.ivysboy.com/?p=593
    https://www.jianshu.com/p/0bff7c020af2

    展开全文
  • python_click.option()使用

    千次阅读 2019-08-19 00:15:30
    click官方文档 click官方文档 click的option详细使用 click.command():将该方法变成一个命令行工具 ...click.option(’–count’, default=1,prompt=‘Your name’,type=int,nargs=1,help=‘Number of...
  • DHCP Option字段

    千次阅读 2017-11-08 13:21:00
    BCMCS Controller IPv4 address option [ RFC4280 ] 90 Authentication N Authentication [ RFC3118 ] 91 client-last-transaction-time option [ RFC4388 ] 92 associated-ip option...
  • javac编译选项-Option

    万次阅读 2018-10-23 14:17:22
    关于这个option所对应的类就是Option.接下来我们就来看一下这个类 解析 Option类是一个枚举,代表javac的选项.处理命令行选项的特定选项是通过按顺序搜索此枚举的成员来标识的,找到第一个匹配的. 其中,Option又分为...
  • DHCP Option 82详细讲解

    千次阅读 2018-05-08 11:00:11
    option 82是dhcp报文中的中继代理信息选项(relay agent information option)。当dhcp client发送请求报文到dhcp server时,若需要经过dhcp中继,则由dhcp中继将option 82添加到请求报文中。option 82包含很多...
  • select option 显示隐藏

    千次阅读 2017-11-17 13:15:27
    <!... ... ... <script type="text/javascript" src="js/jquery-1.9.1.min.js"></script> ... //$('#s2 option[value="s2_6"]').hide();... <option value="s2_10" id="s2_10">10</option>    
  • Mac 系统option键的妙用

    千次阅读 2020-12-16 17:55:13
    一、option + finder 1、文件默认打开方式 在Finder中,点击一个文件,单击右键,在「打开方式」中可以选择不同的应用打开文件。如果你想修改默认的打开方式,只需要按住option:「打开方式」就会变成「始终以方式...
  • 下拉框<option>由getdataset()初始化,用下拉框选择某个option后,datasetpath = request.getParameter("");怎么获得<option>中的value值(路径),option有多个每个都有对应的value ``` 。![图片说明]...
  • jquery动态添加option示例

    千次阅读 2018-12-29 10:42:54
    //所以当选中<option>cc</option>这个option的时候,你会发现上边四个alert出来的值是一样的。都是option中的文本。 //想要拿到option中的value的值,首先option得有value属性啊!!! } ();"> ...
  • b.option(ChannelOption.SO_BACKLOG, 1024 * 1024 * 1024 * 1024); b.option(ChannelOption.SO_SNDBUF, 1024 * 1024 * 1024 * 1024); b.option(ChannelOption.MAX_MESSAGES_PER_READ, Integer.MAX_VALUE); b....
  • mac eclipse option /无效

    千次阅读 2019-04-14 17:04:31
    mac操作系统下eclipse,使用快捷键 option + / (自动补齐代码失效) 解决办法 Eclipse>Preferences>Keys 配置Content Assist的Binding为 ⌥/ Apply and Close 【Java面试题与答案】整理推荐 基础与...
  • Golang 选项模式(Option模式)

    千次阅读 2019-11-28 17:22:06
    Golang 选项模式(Option模式) 一种用于golang函数参数优雅传递的设计模式
  • spark.read.option(jdbc)参数

    千次阅读 2019-10-25 14:43:40
    When specifying `partitionColumn` option is required, the subquery can be specified using `dbtable` option instead and partition columns can be qualified using the subquery alias provided as part of ...
  • 为什么在settings里写,替换不了echarts中option里的值(现在的情况是可以替换title中的text的值,但是不能替换掉其他属性中的值),想问下怎么做可以替换掉option中的任一个属性中的值。 例如: var ...
  • jQuery获取option方法

    千次阅读 2019-07-02 09:48:44
    /获取第一个option的值 $(’#test option:first’).val(); //最后一个option的值 $(’#test option:last’).val(); //获取第二个option的值 $(’#test option:eq(1)’).val(); //获取选中的值 $(’#test’).val(); $...
  • JS动态添加option和删除option

    万次阅读 2017-02-28 15:40:46
    js自动创建和删除option 本文转载自http://www.jb51.net/article/35205.htm 仅供学习之用,留着随时查看动态创建
  • 选中一规格值,另一栏的规格列表隐藏该规格值 ...#spec2 option").show();  var values = $("#spec1").val();  $("#spec2 option[value="+values+"]").hide();  ...
  • scala中的Option

    千次阅读 2019-01-09 14:04:31
    避免null的使用 大多数语言都有一个特殊的关键字或者对象表示一个对象的引用是“无...Scala的Option类型 为了让所有东西都是对象的目标更加一致,也为了遵循函数式编程的习惯,scala鼓励你在变量和函数返回值可能...
  • option 43和option 60

    千次阅读 2017-03-20 15:06:02
    1. Option 60报文结构 option 60格式如下图所示:    Code Len Vendor class Identifier  +-----+-----+-----+-----+---  | 60 | n | i1 | i2 | ...  +-----+-----+-----+-----+---  Code:表示供应商...
  • 5G NR option 3

    千次阅读 2019-05-30 19:07:42
    5G NR option 3网络架构承载类型终端注册流程 网络架构 为了从4G向5G平滑演进,3gpp...初期主流的配置方式都是采用option 3,如下图: 虚线代表控制面,实线代表数据面。 在这种情况下LTE的eNB作为主控节点,5G NR...
  • DHCP option 60 和 option 61

    万次阅读 2017-09-12 14:17:30
    option 60 和 option 61 是2个常见的 DHCP optionoption 60 (Class Id)可以防止非法客户端获取合法ip client 向 DHCP Server 发送 DHCP Discovery 请求,请求中附带 option 60 属性来标示供应商类别标识符。 DHCP ...
  • OPTION 125

    万次阅读 2017-09-06 10:35:50
    DHCP option 125(Vendor-ldentifying Vendor Options):官方定义:option 125是对标准DHCP协议一个补充标准,作用就是让客户端对DHCP服务器也进行认证,防止DHCP服务器伪造。个人总结: option 125 是client ...
  • DHCP Option 对应含义整理

    千次阅读 2020-05-20 09:47:36
    DHCP option 1 设置子网掩码选项。 3 设置网关地址选项。 6 设置DNS服务器地址选项。 12 设置域名选项。 15 设置域名后缀选项。 33设置静态路由选项。该选项中包含一组有分类静态路由(即目的地址的掩码固定...
  • element-UI 下拉框el-select组件el-option的v-for问题 我的代码: &lt;template&gt; &lt;div id="htmlWrap"&gt; &lt;!--header--&gt; &lt;div class="bg545C64"...
  • 1. $("#select_id").append("<option value='Value'>Text</option>"); //为Select追加一个Option(下拉项)  2. $("#select_id").prepend("<option value='0'>请选择</option>"); //为Select插入一个Option(第一个...
  • 前端小白篇之select和option样式修改

    千次阅读 2020-05-28 11:35:36
    本文主要介绍select和option样式"太丑"的解决方案,本文主要是通过vue实现的DOM截点的操作,如非vue需用相关语法的方式获取对应的参数方法。 一、业务场景 1.1 顶栏或横向导航需要一个下拉框,虽然select样式可以...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 986,432
精华内容 394,572
关键字:

option