关于bind:bind-socket报EACCESPermission-denied错误

应用的端口是443端口。 通过apk运行bin文件中的bind socket办法,始终报EACCES (Permission denied)谬误。 查网上材料,根本解决办法都是加权限以及不在UI线程中运行连贯网络的局部,我按此批改了之后,都没有成果。 预计是因为端口号是443端口,是保留端口的缘故? 查bind的文档,针对此谬误的解释: EACCES The address is protected, and the user is not the superuser. 间接运行此bin文件没有问题,是因为此时是superuser吧。参考链接:4 ways to fix bind permission denied in Linux

August 23, 2022 · 1 min · jiezi

关于iot:聊聊LiteOS中生成的BinHEXELF三种文件格式

摘要:咱们在应用编译器在编译工程后会要求生成可执行文件,将这些文件烧录到MCU进行运行,达到咱们测试和应用程序的目标,再应用工具链进行编译的时候往往生成.bin、.hex 、.elf 、.alf等文件,这些文件有什么区别呢?能够相互转换吗?LiteOS 有哪些可执行文件呢?本文意义进行论述。本文分享自华为云社区《LiteOS 下载到MCU中的三种文件格式Bin、HEX、ELF》,原文作者:o0龙龙0o。 咱们在应用编译器在编译工程后会要求生成可执行文件,将这些文件烧录到MCU进行运行,达到咱们测试和应用程序的目标,再应用工具链进行编译的时候往往生成.bin、.hex 、.elf 、.alf等文件,这些文件有什么区别呢?能够相互转换吗?LiteOS 有哪些可执行文件呢?本文意义进行论述。 BINbin文件,是根本的二进制文件,是flash中IO保留的根本信息,是有汇编程序间接汇编失去的二进制代码,bin文件采纳程序记录flash中的信息,文本自身蕴含任任何地址信息,bin文件烧录就是指定flash开始地址后一一拷贝即可。利用STM32CubeProm将LiteOS编译后生成的bin文件显示如下图,咱们须要设定flash写入地址能力进行烧录。 HEXhex文件格式是能够烧写到单片机中,被单片机执行的一种文件格式,生成Hex文件的形式有很多种,能够通过不同的编译器将C程序或者汇编程序编译生成hex;最罕用的Hex格局是Intel HEX文件格式,即遵循Intel HEX文件格式的ASCII文本文件,文件的每一行都蕴含了 一个HEX记录。这些记录是由一些代表机器语言代码和常量的16进制数据组成的。Intel HEX文件罕用来传输要存储在ROM 或者 EPROM中的程序和数据。大部分的EPROM编程器和FLASH能应用Intel HEX文件。 下面的Huawei_LiteOS.bin对应的HEX文件如下(用notepad++关上) :020000040800F2:2000000000000820F50E0008650F0008650F0008650F0008650F0008650F00080000000041:20002000000000000000000000000000650F0008650F000800000000650F0008650F0008D0...........................................................................................................................................................................................................................:208E0000D883050828830508D4820508148505081C8505082485050868CC03082C850508C8:0C8E20003485050804CD030804CD0308C8:00000001FF文件会有头尾部的的阐明。 文件头部的信息 :020000040800F202带边数据长度;紧跟着前面的0x00 0x00 为地址;再前面的0x04为数据类型,类型共分以下几类: '00' //数据记录'01' //文件完结记录'02' //扩大段地址记录'03' //开始段地址记录'04' //扩大线性地址记录'05' //开始线性地址记录接着0x04前面的两个 0x08 0x00就是数据,示意偏移地址,最初一个0xF2是校验码。 第二行开始的记录地址和所对应的数据其格局是 :开始代码|地址|数据类型|数据|校验 :20|0000|00|00000820F50E0008650F0008650F0008650F0008650F0008650F000800000000|41:20 记录数据长度为20个字节;0000 数据在内中的起始地址00 记录类型00(是一个数据记录)00000820F50E0008650F0008650F0008650F0008650F0008650F000800000000 数据内容41 这一行的校验 最初一行的内容示意文件完结记录 :00000001FFhex文件同一样能够在STM32CubeProm打印出内存的内容(与之前的bin打印是统一的)。 ELF在计算机科学中,是一种用于二进制文件、可执行文件、指标代码、共享库和外围转储格式文件,是UNIX零碎实验室(USL)作为应用程序二进制接口(Application Binary Interface,ABI)而开发和公布的,也是Linux的次要可执行文件格局。 elf(Executable and Linkable Format)可执行与可链接格局,是有别于hex和bin通过记录数据的格局,elf更多而记录程序的连贯转储的格式文件,elf指标文件是由汇编器(assembler)和连贯编辑器(link editor)生成的,内容是二进制,而非可读的文本模式,是能够间接在处理器上运行的代码。 简略的了解,elf文件将二进制(bin)文件和程序形容文件打包后的一种执行文件,下载到程序里的仍然是bin文件的局部,然而仿真器能够依附其余程序表述文件来获取程序执行的地位和二进制的对应。表意文件能够利用readelf在linux下读取,因为我零碎的起因就不赘述了。 其余可执行文件: .asf、.o、.out这些文件都是编译后的可执行文件,和elf以鼓吹都是具备连贯格局进行形容,能够利用仿真器进行仿真应用,只是编译格局和编译器设置的不同能够抉择不同的文件格式。 可转换性因为bin、hex都是只是记录数据的,但elf类型不仅记录数据还有程序形容,所以,elf能够转成bin和hex应用,然而反转。 比照一下,发现bin文件最小最简略,然而安全性差,功能性差,hex蕴含头尾和测验,就有很好的安全性,然而文件比bin大,性能没有elf弱小;elf性能多,然而文件最大。 LIteOS如何生成这些文件的liteOS通过makefile进行文件编译,也是通过makefile进行设置gcc编译文件的输入格局,在工程目录下的makefile代码中: $(LD) $(LITEOS_LDFLAGS) $(LITEOS_TABLES_LDFLAGS) $(LITEOS_DYNLDFLAGS) -Map=$(OUT)/$@.map -o $(OUT)/$@.elf --start-group $(LITEOS_BASELIB) --end-group $(OBJCOPY) -O binary $(OUT)/$@.elf $(OUT)/$@.bin $(OBJDUMP) -t $(OUT)/$@.elf |sort >$(OUT)/$@.sym.sorted $(OBJDUMP) -d $(OUT)/$@.elf >$(OUT)/$@.asm $(SIZE) $(OUT)/$@.elf代码中的解释后的代码 ...

March 26, 2021 · 1 min · jiezi

关于bind:centso7-部署bind993mysql56

1.先装置MySQL,间接yum装置* yum -y install mysql mysql-server2.再装置一些依赖的包 yum -y install openssl openssl-devel libss-dev gcc gcc-c++ mysql-devel3.下载bind, bind官网(https://www.isc.org/)wget ftp://ftp.isc.org/isc/bind9/bind-9.10.3-P2/bind-9.10.3-P2.tar.gz4.下载mysql-bind 补丁源码wget http://nchc.dl.sourceforge.net/project/mysql-bind/mysql-bind/mysql-bind-0.2%20src/mysql-bind.tar.gz5.解压bind和mysql-bind源码压缩文件    tar zxvf bind-9.10.3-P2.tar.gz    tar zxvf mysql-bind.tar.gz6.将mysql-bind源码目录下的mysqldb.c 和 mysqldb.h拷贝到bind源码目录下的bin/named和bin/named/include/ 目录下    cd mysql-bind    cp -f mysqldb.c mysqldb.h ../bind-9.10.3-P2/bin/named/    cp -f mysqldb.c mysqldb.h ../bind-9.10.3-P2/bin/named/include/7.批改bind源码目录下bin/named/Makefile.in文件    cd ../bind-9.10.3-P2    vim bin/named/Makefile.in    将以下几行:      DBDRIVER_OBJS =                              DBDRIVER_SRCS =                              DBDRIVER_INCLUDES =                          DBDRIVER_LIBS =    批改为:    DBDRIVER_OBJS = mysqldb.@O@    DBDRIVER_SRCS = mysqldb.c    DBDRIVER_INCLUDES = -I/usr/include/mysql  -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fno-strict-aliasing -fwrapv -fPIC   -DUNIV_LINUX -DUNIV_LINUX    DBDRIVER_LIBS = -rdynamic -L/usr/lib64/mysql -lmysqlclient -lz -lcrypt -lnsl -lm -lssl -lcrypto    DBDRIVER_INCLUDES 的值是通过 mysql_config --cflags 命令获取的    DBDRIVER_LIBS 的值是通过 mysql_config --libs 命令获取的8.批改bind源码目录下bin/named目录下的main.c文件    vim bin/named/main.c    退出 #include "mysqldb.h"    如下:#include <config.h>#include "mysqldb.h"#include <ctype.h>#include <stdlib.h>#include <string.h>     而后在正文代码段 /*  xxdb_init(); */ 后退出 mysqldb_init();    在正文代码段 /*  xxdb_clear(); */后退出 mysqldb_clear();9.批改mysqldb.c批改mysqldb.c中的#include <named/mysqldb.h>为 #include <include/mysqldb.h>10.装置bind    ./configure --prefix=/usr/local/bind --enable-threads  # 指定装置目录和开启多线程的解决能力    make    make install11.配置bind    cd /usr/local/bind-9.10/etc    /usr/local/bind/sbin/rndc-confgen -r /dev/urandom>rndc.conf    cat rndc.conf|tail |head -9 |sed "s/^#//g">named.conf   # 生成配置文件12.创立一个数据库############这版不太好用    Create database mydomain;    创立一张数据表    CREATE TABLE dnsrecord (       name varchar(255) default NULL,      ttl int(11) default NULL,       rdtype varchar(255) default NULL,      rdata varchar(255) default NULL )TYPE=MyISAM;    插入一些测试数据    INSERT INTO dnsrecord VALUES ('test.net', 259200, 'SOA', 'test.net.  www.test.net  200505101 28800 7200 86400 28800');    INSERT INTO dnsrecord VALUES ('test.net', 259200, 'NS', 'ns1.test.net.');    INSERT INTO dnsrecord VALUES ('ns1.test.net', 259200, 'A', '192.168.2.2');    INSERT INTO dnsrecord VALUES ('www.test.net', 259200, 'A', '192.168.2.1');##########################好使###############################DROP TABLE IF EXISTS 10_outside;CREATE TABLE 10_outside ( name varchar(255) default NULL, ttl int(11) default NULL, rdtype varchar(255) default NULL, rdata varchar(255) default NULL);---- Dumping data for table `10_outside`--LOCK TABLES 10_outside WRITE;INSERT INTO 10_outside VALUES ('25.71.210.10.in-addr.arpa',3600,'PTR','cas1.test.mydomain.com.cn.');INSERT INTO 10_outside VALUES ('10.in-addr.arpa',3600,'SOA','test.mydomain.com.cn. zhengyu.staff.mydomain.com.cn. 20070319 1800 600 604800 600');INSERT INTO 10_outside VALUES ('10.in-addr.arpa',3600,'NS','cas1.test.mydomain.com.cn.');INSERT INTO 10_outside VALUES ('10.in-addr.arpa',3600,'NS','cas2.test.mydomain.com.cn.');INSERT INTO 10_outside VALUES ('10.in-addr.arpa',3600,'NS','cas3.test.mydomain.com.cn.');INSERT INTO 10_outside VALUES ('27.71.210.10.in-addr.arpa',3600,'PTR','cas2.test.mydomain.com.cn.');UNLOCK TABLES;---- Table structure for table `test_mydomain_com_cn_outside`--DROP TABLE IF EXISTS test_mydomain_com_cn_outside;CREATE TABLE test_mydomain_com_cn_outside ( name varchar(255) default NULL, ttl int(11) default NULL, rdtype varchar(255) default NULL, rdata varchar(255) default NULL);---- Dumping data for table `test_mydomain_com_cn_outside`--LOCK TABLES test_mydomain_com_cn_outside WRITE;INSERT INTO test_mydomain_com_cn_outside VALUES ('test.mydomain.com.cn',3600,'SOA','test.mydomain.com.cn. zhengyu.staff.mydomain.com.cn. 20070319 1800 600 604800 600');INSERT INTO test_mydomain_com_cn_outside VALUES ('test.mydomain.com.cn',3600,'NS','cas1.test.mydomain.com.cn.');INSERT INTO test_mydomain_com_cn_outside VALUES ('test.mydomain.com.cn',3600,'NS','cas2.test.mydomain.com.cn.');INSERT INTO test_mydomain_com_cn_outside VALUES ('test.mydomain.com.cn',3600,'NS','cas3.test.mydomain.com.cn.');INSERT INTO test_mydomain_com_cn_outside VALUES ('cas1.test.mydomain.com.cn',3600,'A','10.210.71.25');INSERT INTO test_mydomain_com_cn_outside VALUES ('cas2.test.mydomain.com.cn',3600,'A','10.210.71.27');INSERT INTO test_mydomain_com_cn_outside VALUES ('cas3.test.mydomain.com.cn',3600,'A','10.210.132.80');INSERT INTO test_mydomain_com_cn_outside VALUES ('yhzh.test.mydomain.com.cn',3600,'A','10.218.26.191');INSERT INTO test_mydomain_com_cn_outside VALUES ('yhzh.test.mydomain.com.cn',3600,'A','10.218.26.192');INSERT INTO test_mydomain_com_cn_outside VALUES ('yhzh.test.mydomain.com.cn',3600,'A','10.218.26.193');INSERT INTO test_mydomain_com_cn_outside VALUES ('yhzh.test.mydomain.com.cn',3600,'A','10.218.26.194');INSERT INTO test_mydomain_com_cn_outside VALUES ('*',3600,'A','10.210.71.1');INSERT INTO test_mydomain_com_cn_outside VALUES ('conf.test.mydomain.com.cn',3600,'CNAME','cas2.test.mydomain.com.cn.');UNLOCK TABLES;############################################13.持续配置bind vim /usr/local/bind/etc/named.conf在前面依照以下格局退出zone "mydomain.com" {    type master;    notify no;     database "mysqldb dbname tablename hostname user password"; };mydomain.com为要解析的域名dbname 为数据库名hostname为数据库服务器地址user 为可操作后面数据库表的数据库用户名password 为对应数据库用户名的明码配置实现在命令行下运行/usr/local/bind/sbin/named -c /usr/local/bind/etc/named.conf -g查看没问题后/usr/local/bind/sbin/named -c /usr/local/bind/etc/named.conf [root@silence etc]# lsbind.keys named.conf named.root rndc.conf root.zone[root@silence etc]# cat root.zone $TTL 86400@ IN SOA ns1.mydomain.com. w1.mydomain.com ( 2018070110 1H 5M 7D 1D) IN NS ns1 IN NS ns2 IN MX 10 mx1 IN MX 20 mx2ns1 IN A 192.168.108.160ns2 IN A 192.168.108.138ns3 IN A 192.168.108.166mx1 IN A 192.168.108.138w1 IN A 192.168.1.2w0 IN A 192.168.1.1www IN A 192.168.108.160* IN A 192.168.108.166[root@silence etc]# cat named.conf key "rndc-key" { algorithm hmac-md5; secret "ZYobWCcSDr2HDCMuojc6gg=="; }; controls { inet 127.0.0.1 port 953 allow { 127.0.0.1; } keys { "rndc-key"; }; };options { listen-on port 53 { 127.0.0.1;172.16.188.123; }; directory "/data/work/bind9.9.3"; allow-query-cache { any; }; allow-query { any; }; dnssec-enable yes; dnssec-validation yes; dnssec-lookaside auto; }; zone "." { type hint; file "/data/work/bind9.9.3/etc/root.zone"; }; zone "mydomain" { type forward; forwarders { 114.114.114.114;8.8.8.8; }; forward first; }; logging { channel bind_log { file "/data/work/bind9.9.3/logs/bind.log" versions 3 size 20m; severity info; print-time yes; print-severity yes; print-category yes; }; category default { bind_log; }; }; zone "test.mydomain.com.cn" IN{ type master; notify no; database "mysqldb mydomain test_mydomain_com_cn_outside 172.16.188.123 root 111111"; }; zone "16.172.in-addr.arpa" IN{ type master; notify no; database "mysqldb mydomain 10_outside 172.16.188.123 root 111111"; };运行bind ...

November 25, 2020 · 7 min · jiezi

关于bind:商业智能Business-Intelligence系统的使用及设计原则

各类通过编纂与汇总的数据,是信息时代下的标志性产物。身处于当今由前沿网络技术所引领的社会,大数据曾经俨然成为一种贵重的资源与财产。当然,各种数据在没有系统化的整顿之前,还不过是一段段无意义的信息碎片,咱们很难从大量的碎片中获取到有价值的货色。只有通过高效的可视化剖析工具,能力直观的获取到大数据所带来的资源,为各项策略的制订提供参考。 而当今最高效最直观的解决方案,便是是商业智能(Business Intelligence)零碎可视化大屏。商业智能零碎堪称是展示外围数据的最优工具,它能够将业务的要害指标以图表动画的形式展现到多块屏幕,不仅可让业务人员疾速、精确地从繁冗的材料中找到要害数据,更能为决策人员提供重要参考。 XJR商业智能设计器 这里以XJR商业智能插件为例,来介绍一下可视化大屏的利用及设计规定。 一、何为数据可视化 艰深来讲,其实就是图形化数据,将其清晰无效的表达出来。可直观的将数据出现,便于查看,还能减速开掘数据中暗藏的价值。其本质是可视、可交换、可互动。而且应用大尺寸屏幕来展现数据,其浓烈的科技感容易震撼初用者的第一印象,便于营造特定气氛或典礼感。利用其面积大、可展现信息多的特点,便于多人同时查看,数据能够共享展示,便于团队探讨和决策。 二、可视化大屏次要利用场景 目前次要利用在以政府机关、商业机构、金融中心、实业制作等行业的业务场景中,大数据的价值在此失去充沛展示。比方,数据大屏作为一种无效传递信息的伎俩,正在城市智能经营核心、应急指挥核心、执法监控核心、电力调度核心、金融交易大厅等部门和机构中承当起重要的角色。具备日常监测、剖析研判、应急指挥、展现汇报等多种性能,在帮忙发展科学管理工作等方面发挥作用。这里提供一些行业模板,以作参考。 通用模板 金融服务平台 品牌手机销量剖析 挪动通信IOP大数据平台 疫情防控数据平台 机房设备数据平台 房产物业数据平台 财务数据核心 三、可视化大屏设计准则 或者,人们对可视化大屏的第一印象就是炫酷,但这只是体面,清晰无效的传播数据,才是大屏的里子。 通常有多种类型的资源及数据须要在大屏中展现进去,不过在显示前须要进行页面布局来将主排布主次,明确层级关系和流向,使观看者疾速获取信息的同时,也能均衡视觉。 惯例状况下,企业要开发出一款大屏,须要经验:需要沟通——大屏UI设计——大屏数据开发——大屏前端开发。过程中遵循以下准则:总览优先,细节辅助。 服务于业务,让业务指标和数据正当的展示,因为须要展示的是整个企业的全局业务,故分为次要指标和主要指标两种,次要指标反映外围业务,主要指标用于论述详情,所以在制作时给予不一样的偏重。 优良的UI设计,让使用者更高效更舒服地获取信息。配色的学识次要是背景色,背景色又分为整体背景和元素的背景,无论是哪一个,都听从两点根本准则:深色和谐一致性。深色调是为了防止视觉刺激。 减少动画能让大屏看上去是活的,优化观感体验,不过要把握好度,过分的动效容易喧宾夺主,扰乱使用者的思路,不利于决策者思考与剖析。 目前市面上尽管有泛滥可视化工具,然而大都两极分化重大。大部分为了凸显其性能而设计得枯燥乏味,多数则为了壮丽而壮丽金玉其外;败絮其中,决策者都难以从中获取数据的真正价值。 XJR商业智能插件是基于浏览器的、用于配置数据可视化大屏的工具平台。它提供了丰盛的可视化设计组件,通过简略鼠标操作,即可进行图表布局的调整,能在数分钟内配置出好看实用的BI零碎。 XJR商业智能旨在帮忙企业进行内外部数据整合、数据治理、摸索式剖析以及实现智能化决策。赋予企业大数据分析能力,助力企业构建数据生态系统,帮忙企业降本增收和实现数据资产的变现。 参考资料起源:https://www.xjrsoft.com/

September 16, 2020 · 1 min · jiezi

ES5-callapplybind方法总结包括理解this的指向问题

总结call,apply,bind方法的理解使用和区别。call,apply,bind这三个方法在JavaScript中是用来改变函数调用的this指向。那么改变函数this指向有什么用呢?我们先来看一段代码 var a= { name:'harden', fn:function () { console.log(this.name); }}var b = a.fn;a.fn();//hardenb();//undefined调用a.fn方法后得到了harden,但在b方法中我想得到harden,为什么却是undefined呢?原因是方法在执行的时候才能确定this到底指向谁,实际上this指向的是最终调用函数的对象。这里当b执行时,实际是window调用了fn函数,那么fn中的this就指向window。在开始讲call,apply,bind方法前,一起来总结一下this的指向问题。 理解JavaScript中的this指向问题。总体来说this指向可以概括为一句话:this指向在函数的定义时是不确定的,只有函数执行时才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象。但是这个说法在函数被很多对象包裹的时候并不成立,请看下面例子。简单来说就是:谁(哪个对象)调用的这个函数,那么这个函数中的this就指向这个对象。 例一 function a(){ var name= "harden"; console.log(this.name); //undefined console.log(this); //Window } a();因为this最终指向调用他的对象,在上述代码中其实是widow触发的这个方法,那么this就指向window,window中并没有定义a,那么就打印出undefined。例二: var a = { name:'harden', fn:function() { console.log(this.name);//harden console.log(this);//指向a(可以自己跑一下) }}a.fn()这里的this指向a,因为这里的fn函数是通过a.fn()执行的,那么this自然指向a。说到这我就有疑问了,如果我用 window.a.fn()执行函数,this不就指向window了吗?然后并不是这样的,请看下一个例子。补充一点:window是js的全局对象。例三: var a = { name:'harden', b:{ name:'james', fn:function() { console.log(this.name);//james console.log(this);//指向b } }}a.b.fn()我们看到最终是a调用的方法,那为什么this会指向b呢?现在总结三句话,来完全理解this的指向问题: 情况一:如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window(除去严格模式外)。情况二:如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。情况三:如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象,例子3可以证明。 构造函数中的this: function Fn(){ this.name = "harden"; } var a = new Fn(); console.log(a.name); //harden这里的a可以点出name,因为new关键字会改变this的指向。为什么new关键字会改变this呢,我自己有两种看法:1.在new的过程中会创建一个实例对象,通过apply等方法 通过 Fn.apply({}) 使this指向这个空对象,最后把fn方法中的材料加工完后返回给a。 ...

June 21, 2019 · 1 min · jiezi

JavaScript进阶之模拟call,apply和bind

原文:https://zhehuaxuan.github.io/… 作者:zhehuaxuan目的本文主要用于理解和掌握call,apply和bind的使用和原理,本文适用于对它们的用法不是很熟悉,或者想搞清楚它们原理的童鞋。 好,那我们开始! 在JavaScript中有三种方式来改变this的作用域call,apply和bind。我们先来看看它们是怎么用的,只有知道怎么用的,我们才能来模拟它。Function.prototype.call()首先是Function.prototype.call(),不熟的童鞋请猛戳MDN,它是这么说的:call()允许为不同的对象分配和调用属于一个对象的函数/方法。也就是说:一个函数,只要调用call()方法,就可以把它分配给不同的对象。如果还是不明白,不急!跟我往下看,我们先来写一个call()函数最简单的用法:function source(){ console.log(this.name); //打印 xuan}let destination = { name:“xuan”};console.log(source.call(destination));上述代码会打印出destination的name属性,也就是说source()函数通过调用call(),source()函数中的this对象可以分配到destination对象中。类似于实现destination.source()的效果,当然前提是destination要有一个source属性好,现在大家应该明白call()的基本用法,我们再来看下面的例子:function source(age,gender){ console.log(this.name); console.log(age); console.log(gender);}let destination = { name:“xuan”};console.log(source.call(destination,18,“male”));打印效果如下:我们可以看到可以call()也可以传参,而且是以参数,参数,…的形式传入。上述我们知道call()的两个作用:1.改变this的指向2.支持对函数传参我们看到最后还还输出一个undefined,说明现在调用source.call(…args)没有返回值。我们给source函数添加一个返回值试一下:function source(age,gender){ console.log(this.name); console.log(age); console.log(gender); //添加一个返回值对象 return { age:age, gender:gender, name:this.name }}let destination = { name:“xuan”};console.log(source.call(destination,18,“male”));打印结果:果不其然!call()函数的返回值就是source函数的返回值,那么call()函数的作用已经很明显了。这边再总结一下:改变this的指向支持对函数传参函数返回什么,call就返回什么。模拟Function.prototype.call()根据call()函数的作用,我们下面一步一步的进行模拟。我们先把上面的部分代码摘抄下来:function source(age,gender){ console.log(this.name); console.log(age); console.log(gender); //添加一个返回值对象 return { age:age, gender:gender, name:this.name }}let destination = { name:“xuan”};上面的这部分代码我们先不变。现在只要实现一个函数call1()并使用下面方式console.log(source.call1(destination));如果得出的结果和call()函数一样,那就没问题了。现在我们来模拟第一步:改变this的指向。假设我们destination的结构是这样的:let destination = { name:“xuan”, source:function(age,gender){ console.log(this.name); console.log(age); console.log(gender); //添加一个返回值对象 return { age:age, gender:gender, name:this.name } }}我们执行destination.source(18,“male”);就可以在source()函数中把正确的结果打印出来并且返回我们想要的值。现在我们的目的更明确了:给destination对象添加一个source属性,然后添加参数执行它。所以我们定义如下:Function.prototype.call1 = function(ctx){ ctx.fn = this; //ctx为destination this指向source 那么就是destination.fn = source; ctx.fn(); // 执行函数 delete ctx.fn; //在删除这个属性}console.log(source.call1(destination,18,“male”));打印效果如下:我们发现this的指向已经改变了,但是我们传入的参数还没有处理。第二步:支持对函数传参。 我们使用ES6语法修改如下:Function.prototype.call1 =function(ctx,…args){ ctx.fn = this; ctx.fn(…args); delete ctx.fn;}console.log(source.call1(destination,18,“male”));打印效果如下:参数出现了,现在就剩下返回值了,很简单,我们再修改一下:Function.prototype.call1 =function(ctx,…args){ ctx.fn = this || window; //防止ctx为null的情况 let res = ctx.fn(…args); delete ctx.fn; return res;}console.log(source.call1(destination,18,“male”));打印效果如下:现在我们实现了call的效果!模拟Function.prototype.apply()apply()函数的作用和call()函数一样,只是传参的方式不一样。apply的用法可以查看MDN,MDN这么说的:apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。apply()函数的第二个参数是一个数组,数组是调用apply()的函数的参数。function source(age,gender){ console.log(this.name); console.log(age); console.log(gender); return { age:age, gender:gender, name:this.name }}let destination = { name:“xuan”};console.log(source.apply(destination,[18,“male”]));效果和call()是一样的。既然只是传参不一样,我们把模拟call()函数的代码稍微改改:Function.prototype.apply1 =function(ctx,args=[]){ ctx.fn = this || window; let res = ctx.fn(…args); delete ctx.fn; return res;}console.log(source.apply1(destination,[18,‘male’]));执行效果如下:apply()函数的模拟完成。Function.prototype.bind()对于bind()函数的作用,我们引用MDN,bind()方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this对象,之后的一序列参数将会在传递的实参前传入作为它的参数。我们看一下代码:function source(age,gender){ console.log(this.name); console.log(age); console.log(gender); return { age:age, gender:gender, name:this.name }}let destination = { name:“xuan”};var res = source.bind(destination,18,“male”);console.log(res());console.log("==========================")var res1 = source.bind(destination,18);console.log(res1(“male”));console.log("==========================")var res2 = source.bind(destination);console.log(res2(18,“male”));打印效果如下:我们发现bind函数跟apply和call有两个区别:1.bind返回的是函数,虽然也有call和apply的作用,但是需要在调用bind()时生效2.bind中也可以添加参数明白了区别,下面我们来模拟bind函数。模拟Function.prototype.bind()和模拟call一样,现摘抄下面的代码:function source(age,gender){ console.log(this.name); console.log(age); console.log(gender); //添加一个返回值对象 return { age:age, gender:gender, name:this.name }}let destination = { name:“xuan”};然后我们定义一个函数bind1,如果执行下面的代码能够返回和bind函数一样的值,就达到我们的目的。var res = source.bind1(destination,18);console.log(res(“male”));首先我们定义一个bind1函数,因为返回值是一个函数,所以我们可以这么写:Function.prototype.bind1 = function(ctx,…args){ var that = this;//外层的this指向通过变量传进去 return function(){ //将外层函数的参数和内层函数的参数合并 var all_args = […args].concat([…arguments]); //因为ctx是外层的this指针,在外层我们使用一个变量that引用进来 return that.apply(ctx,all_args); }}打印效果如下:这里我们利用闭包,把外层函数的ctx和参数args传到内层函数,再将内外传递的参数合并,然后使用apply()或call()函数,将其返回。当我们调用res(“male”)时,因为外层ctx和args还是会存在内存当中,所以调用时,前面的ctx也就是source,args也就是18,再将传入的"male"跟18合并[18,‘male’],执行source.apply(destination,[18,‘male’]);返回函数结果即可。bind()的模拟完成!但是bind除了上述用法,还可以有如下用法:function source(age,gender){ console.log(this.name); console.log(age); console.log(gender); //添加一个返回值对象 return { age:age, gender:gender, name:this.name }}let destination = { name:“xuan”};var res = source.bind1(destination,18);var person = new res(“male”);console.log(person);打印效果如下:我们发现bind函数支持new关键字,调用的时候this的绑定失效了,那么new之后,this指向哪里呢?我们来试一下,代码如下:function source(age,gender){ console.log(this);}let destination = { name:“xuan”};var res = source.bind(destination,18);console.log(new res(“male”));console.log(res(“male”));执行new的时候,我们发现虽然bind的第一个参数是destination,但是this是指向source的。不用new的话,this指向destination。好,现在再来回顾一下我们的bind1实现:Function.prototype.bind1 = function(ctx,…args){ var that = this; return function(){ //将外层函数的参数和内层函数的参数合并 var all_args = […args].concat([…arguments]); //因为ctx是外层的this指针,在外层我们使用一个变量that引用进来 return that.apply(ctx,all_args); }}如果我们使用:var res = source.bind(destination,18);console.log(new res(“male”));如果执行上述代码,我们的ctx还是destination,也就是说这个时候下面的source函数中的ctx还是指向destination。而根据Function.prototype.bind的用法,这时this应该是指向source自身。我们先把部分代码抄下来:function source(age,gender){ console.log(this.name); console.log(age); console.log(gender); //添加一个返回值对象 return { age:age, gender:gender, name:this.name }}let destination = { name:“xuan”};我们改一下bind1函数:Function.prototype.bind1 = function (ctx, …args) { var that = this;//that肯定是source //定义了一个函数 let f = function () { //将外层函数的参数和内层函数的参数合并 var all_args = […args].concat([…arguments]); //因为ctx是外层的this指针,在外层我们使用一个变量that引用进来 var real_ctx = this instanceof f ? this : ctx; return that.apply(real_ctx, all_args); } //函数的原型指向source的原型,这样执行new f()的时候this就会通过原型链指向source f.prototype = this.prototype; //返回函数 return f;}我们执行var res = source.bind1(destination,18);console.log(new res(“male”));效果如下:已经达到我们的效果!现在分析一下上述实现的代码://调用var res = source.bind1(destination,18)时的代码分析Function.prototype.bind1 = function (ctx, …args) { var that = this;//that肯定是source //定义了一个函数 let f = function () { … //内部先不管 } //函数的原型指向source的原型,这样执行new f()的时候this就会指向一个新家的对象,这个对象通过原型链指向source,这正是我们上面执行apply的时候需要传入的参数 //f.prototype==>source.prototype f.prototype = this.prototype; //返回函数 return f;}f()函数的内部实现分析://new res(“male”)相当于运行new f(“male”);下面进行函数的运行态分析let f = function () { console.log(this);//这个时候打印this就是一个_proto_指向f.prototype的对象,因为f.prototype==>source.prototype,所以this.proto==>source.prototype //将外层函数的参数和内层函数的参数合并 var all_args = […args].concat([…arguments]); //正常不用new的时候this指向当前调用处的this指针(在全局环境中执行,this就是window对象);使用new的话这个this对象的原型链上有一个类型是f的原型对象。 //那么判断一下,如果this instanceof f,那么real_ctx=this,否则real_ctx=ctx; var real_ctx = this instanceof f ? this : ctx; //现在把真正分配给source函数的对象传入 return that.apply(real_ctx, all_args);}至此bind()函数的模拟实现完毕!如有不对之处,欢迎拍砖!您的宝贵意见是我写作的动力,谢谢大家。 ...

March 14, 2019 · 2 min · jiezi

【Linux系统编程】普通用户绑定(bind)特权端口

有些知识不常使用真的容易忘啊,即使没有忘记,知识提取速度也够下午茶的。背景最近在学Haskell,今天用Haskell的Network.Socket模块实现了一个简单的基于TCP的daytime服务程序。程序运行阶段报了以下的错误:Network.Socket.bind: permission denied (Permission denied)我的第一反应怀疑是不是本地有服务程序占用端口号13,然后用命令netstat -tunl | grep 13查看,端口号并没有占用,所以第一种可能性不成立。是不是这个模块有类似的bug呢?但并没有查到。不放心,用C语言写了同样功能的程序,然后运行也会出错:bind error: Permission denied那是不是端口的问题,隐隐约约记得好像是小于1024的端口号不是预留给用户的。然后换了一个>=1024的端口,果然运行成功了。至此,思路才走上正轨。实际上小于1024的端口是特权端口,普通用户是没有权限绑定的。那如果我就是要用端口13呢,怎么解决呢?解决方案1.使用root权限运行最简单的方式就是登录root帐号,或者使用su切换到root。如果本机有配置sudo,普通用户也可使用该命令运行服务程序。2.使用setcap给服务程序赋予能力上一种方式是使用具有特权的用户,而该种方式是给程序赋予绑定特权端口的能力。操作如下:使用setcap ‘CAP_NET_BIND_SERVICE=+ep’ /path/to/program赋予(raise)绑定特权端口的能力使用setcap ‘CAP_NET_BIND_SERVICE=-ep’ /path/to/program清除(lower)绑定特权端口的能力也可使用setcap -r /path/to/program清除(remove)该程序的所有能力setcap简单使用说明除了CAP_NET_BIND_SERVICE,还有好多能力,可以参考capabilities(7)=、-是运算符,除此之外还有+;e和p是标记,除此之外还有i。可参考cap_from_text(3) Textual Representation一节的说明。setcap命令对内核有要求,必须>=2.6.24。 请关注我的公众号哦。

February 25, 2019 · 1 min · jiezi

「干货」细说 call、apply 以及 bind 的区别和用法未指定标题的文章

前言上一篇文章 《「前端面试题系列4」this 的原理以及用法》 中,提到了 call 和 apply。它们最主要的作用,是改变 this 的指向。在平时的工作中,除了在写一些基础类,或者公用库方法的时候会用到它们,其他时候 call 和 apply 的应用场景并不多。不过,突然遇到的时候,需要想一下才能转过弯来。所以今天,就让我们好好地探究一下,这两个方法的区别以及一些妙用。最后,还会介绍与之用法相似的 bind 的方法。call 和 apply 的共同点它们的共同点是,都能够改变函数执行时的上下文,将一个对象的方法交给另一个对象来执行,并且是立即执行的。为何要改变执行上下文?举一个生活中的小例子:平时没时间做饭的我,周末想给孩子炖个腌笃鲜尝尝。但是没有适合的锅,而我又不想出去买。所以就问邻居借了一个锅来用,这样既达到了目的,又节省了开支,一举两得。改变执行上下文也是一样的,A 对象有一个方法,而 B 对象因为某种原因,也需要用到同样的方法,那么这时候我们是单独为 B 对象扩展一个方法呢,还是借用一下 A 对象的方法呢?当然是借用 A 对象的啦,既完成了需求,又减少了内存的占用。另外,它们的写法也很类似,调用 call 和 apply 的对象,必须是一个函数 Function。接下来,就会说到具体的写法,那也是它们区别的主要体现。call 和 apply 的区别它们的区别,主要体现在参数的写法上。先来看一下它们各自的具体写法。call 的写法Function.call(obj,[param1[,param2[,…[,paramN]]]])需要注意以下几点:调用 call 的对象,必须是个函数 Function。call 的第一个参数,是一个对象。 Function 的调用者,将会指向这个对象。如果不传,则默认为全局对象 window。第二个参数开始,可以接收任意个参数。每个参数会映射到相应位置的 Function 的参数上。但是如果将所有的参数作为数组传入,它们会作为一个整体映射到 Function 对应的第一个参数上,之后参数都为空。function func (a,b,c) {}func.call(obj, 1,2,3)// func 接收到的参数实际上是 1,2,3func.call(obj, [1,2,3])// func 接收到的参数实际上是 [1,2,3],undefined,undefinedapply 的写法Function.apply(obj[,argArray])需要注意的是:它的调用者必须是函数 Function,并且只接收两个参数,第一个参数的规则与 call 一致。第二个参数,必须是数组或者类数组,它们会被转换成类数组,传入 Function 中,并且会被映射到 Function 对应的参数上。这也是 call 和 apply 之间,很重要的一个区别。func.apply(obj, [1,2,3])// func 接收到的参数实际上是 1,2,3func.apply(obj, { 0: 1, 1: 2, 2: 3, length: 3})// func 接收到的参数实际上是 1,2,3什么是类数组?先说数组,这我们都熟悉。它的特征有:可以通过角标调用,如 array[0];具有长度属性length;可以通过 for 循环或forEach方法,进行遍历。那么,类数组是什么呢?顾名思义,就是具备与数组特征类似的对象。比如,下面的这个对象,就是一个类数组。let arrayLike = { 0: 1, 1: 2, 2: 3, length: 3};类数组 arrayLike 可以通过角标进行调用,具有length属性,同时也可以通过 for 循环进行遍历。类数组,还是比较常用的,只是我们平时可能没注意到。比如,我们获取 DOM 节点的方法,返回的就是一个类数组。再比如,在一个方法中使用 arguments 获取到的所有参数,也是一个类数组。但是需要注意的是:类数组无法使用 forEach、splice、push 等数组原型链上的方法,毕竟它不是真正的数组。call 和 apply 的用途下面会分别列举 call 和 apply 的一些使用场景。声明:例子中没有哪个场景是必须用 call 或者必须用 apply 的,只是个人习惯这么用而已。call 的使用场景1、对象的继承。如下面这个例子:function superClass () { this.a = 1; this.print = function () { console.log(this.a); }}function subClass () { superClass.call(this); this.print();}subClass();// 1subClass 通过 call 方法,继承了 superClass 的 print 方法和 a 变量。此外,subClass 还可以扩展自己的其他方法。2、借用方法。还记得刚才的类数组么?如果它想使用 Array 原型链上的方法,可以这样:let domNodes = Array.prototype.slice.call(document.getElementsByTagName("*"));这样,domNodes 就可以应用 Array 下的所有方法了。apply 的一些妙用1、Math.max。用它来获取数组中最大的一项。let max = Math.max.apply(null, array);同理,要获取数组中最小的一项,可以这样:let min = Math.min.apply(null, array);2、实现两个数组合并。在 ES6 的扩展运算符出现之前,我们可以用 Array.prototype.push来实现。let arr1 = [1, 2, 3];let arr2 = [4, 5, 6];Array.prototype.push.apply(arr1, arr2);console.log(arr1); // [1, 2, 3, 4, 5, 6]bind 的使用最后来说说 bind。在 MDN 上的解释是:bind() 方法创建一个新的函数,在调用时设置 this 关键字为提供的值。并在调用新函数时,将给定参数列表作为原函数的参数序列的前若干项。它的语法如下:Function.bind(thisArg[, arg1[, arg2[, …]]])bind 方法 与 apply 和 call 比较类似,也能改变函数体内的 this 指向。不同的是,bind 方法的返回值是函数,并且需要稍后调用,才会执行。而 apply 和 call 则是立即调用。来看下面这个例子:function add (a, b) { return a + b;}function sub (a, b) { return a - b;}add.bind(sub, 5, 3); // 这时,并不会返回 8add.bind(sub, 5, 3)(); // 调用后,返回 8如果 bind 的第一个参数是 null 或者 undefined,this 就指向全局对象 window。总结call 和 apply 的主要作用,是改变对象的执行上下文,并且是立即执行的。它们在参数上的写法略有区别。bind 也能改变对象的执行上下文,它与 call 和 apply 不同的是,返回值是一个函数,并且需要稍后再调用一下,才会执行。最后,分享一个在知乎上看到的,关于 call 和 apply 的便捷记忆法:猫吃鱼,狗吃肉,奥特曼打小怪兽。有天狗想吃鱼了猫.吃鱼.call(狗,鱼)狗就吃到鱼了猫成精了,想打怪兽奥特曼.打小怪兽.call(猫,小怪兽)猫也可以打小怪兽了PS:欢迎关注我的公众号 “超哥前端小栈”,交流更多的想法与技术。 ...

January 27, 2019 · 2 min · jiezi

Javascript currying柯里化详解

面试题:实现add(1)(2)(3) //结果 = 6,题的核心就是问的js的柯里化先说说什么是柯里化,看过许多关于柯里化的文章,始终搞不太清楚,例如:柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。大多数的blog都是这种说法,说实话我是懵逼的。我的理解是,curry是一个收集参数的方法,收集够了去执行函数。实现前我们先列一下要点1、收集参数(就像面试题多次执行多个参数)是的利用闭包2、每次执行参数有多有少例如add(1)(2,3)(4)3、我们需要知道什么时候参数够了 //如题 //add(1)(2)(3) //逻辑应该是这样add(1)执行收集参数1继续执行收集参数2依次类推直到收集完毕。 function curry(fn) { let arg = []; //用于收集参数 //做一个闭包https://segmentfault.com/a/1190000017824877 return function() { //每执行一次收集一次参数,为什么用concat是因为有时候后是多个参数(2,3) arg = arg.concat([…arguments]); //直到参数收集完成执行fn // 我们需要知道什么时候收集完了,条件就是curry参数fn的参数个数 fn.length //如果收集的参数个数大于等于fn的参数个数执行fn,如果没有递归执行 if (arg.length >= fn.length) { return fn(…arg) } // 参数没有收集完我们需要继续收集,递归 return arguments.callee } } // 测试一下 let testAdd = curry(add1) // console.log(testAdd(1)(2)(3)) // console.log(testAdd(1, 2)(3)) //console.log(testAdd(1)(2, 3))一不小心写完了!不过不能标题党,说好的详解,接下来我们解析一下网上大多数柯里化的实现代码function curry(fn) { function _c(restNum, argsList) { return restNum === 0 ? fn.apply(null, argsList) : function(x) { return _c(restNum - 1, argsList.concat(x)); }; } return _c(fn.length, []);}一眼看不明白没事,我们多看几眼。解析:1、curry也是接收一个参数(fn)这个是必然2、返回了一个函数,接收两个参数,fn.length和一个空数组这个好解释,我写的简版也说过了,fn.length是为了判断参数是否收集够了,参数传一个空数组其实也是闭包的一种实现,用来收集参数。 3、里边是一个三目判断,看着花里胡哨的没那么复杂,判断fn的参数个数如果是0,那就没必要收集了直接执行fn,至于fn.apply(null,argList)我很明白的大声说出来会用个apply就到处用吗?在我看来没有一分钱用,之所以用是因为argList是一个数组,正好apply正好支持第二个参数是数组,主要看起来很牛逼的样子。4、收集参数,fn参数个数不为零,每次收集fn函数参数的个数减一,直到等于0执行fn,这个就没有我写的通用了,我一次传俩就挂了。再来一个例子:bind方法实现Function.prototype.bind = function(context) { //返回一个绑定this的函数,我们需要在此保存this let self = this // 可以支持柯里化传参,保存参数 let arg = […arguments].slice(1) // 返回一个函数 return function() { //同样因为支持柯里化形式传参我们需要再次获取存储参数 let newArg = […arguments] console.log(newArg) // 返回函数绑定this,传入两次保存的参数 //考虑返回函数有返回值做了return return self.apply(context, arg.concat(newArg)) } } // 搞定测试 let fn = Person.say.bind(Person1) fn() fn(18)是的bind方法就是用的柯里化,bind实现详情请移步:https://segmentfault.com/a/11… ...

January 23, 2019 · 1 min · jiezi

typescript 3.2 新编译选项strictBindCallApply

突发错误我的gels项目(https://github.com/zhoutk/gels),几天没动,突然tsc编译出错,信息如下:src/app.ts:28:38 - error TS2345: Argument of type ‘any[]’ is not assignable to parameter of type ‘[Middleware<ParameterizedContext<any, {}>>]’. Property ‘0’ is missing in type ‘any[]’ but required in type ‘[Middleware<ParameterizedContext<any, {}>>]’.28 m && (app.use.apply(app, [].concat(m)))我的源代码,是动态加载Koa的中间件,app是koa2实例 for (let m of [].concat(middleware)) { m && (app.use.apply(app, [].concat(m))) }问题分析几天前还是正常编译、正常运行的项目,突然出错,应该是环境变了。经查找,发现全局typescript已经升级到了最新版本,3.2.2,而项目中的版本是3.0.3。 将全局版本换回3.0.3,编译通过,问题找到。问题定位上typescrpt的github主页,找发布日志,发现3.2的新功能,第一条就是:TypeScript 3.2 introduces a new –strictBindCallApply compiler option (in the –strict family of options) with which the bind, call, and apply methods on function objects are strongly typed and strictly checked.大概意思是:TypeScript 3.2引入一个新的编译选项 –strictBindCallApply,若使用这个选项,函数对象的bind,call和apply方法是强类型的,并进行严格检测。解决方案因为是动态参数,想了半天我没法明确声明类型。因此,我在tsconfig.json配置文件中,设置"strictBindCallApply": false,将这个编译选项关闭,这样就可以将typescript升级到3.2.2了。哪位朋友若有能打开strictBindCallApply选项,又能通过编译的方案,烦请告知一下,谢谢!我若哪天找到方法,会马上更新本文章。 ...

January 2, 2019 · 1 min · jiezi