最近在面试,总结总结遇到的面试题.
基础问题
LRU算法
[内存管理]的一种页面置换算法,对于在内存中但又不用的[数据块](内存块)叫做LRU,操作系统会根据哪些数据属于LRU而将其移出内存而腾出空间来加载另外的数据,常用于页面置换算法,是为虚拟页式存储管理服务的。
设计原则
如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰。
实现LRU
- 1.用一个数组来存储数据,给每一个数据项标记一个访问时间戳,每次插入新数据项的时候,先把数组中存在的数据项的时间戳自增,并将新数据项的时间戳置为0并插入到数组中。每次访问数组中的数据项的时候,将被访问的数据项的时间戳置为0。当数组空间已满时,将时间戳最大的数据项淘汰。
- 2.利用一个链表来实现,每次新插入数据的时候将新数据插到链表的头部;每次缓存命中(即数据被访问),则将数据移到链表头部;那么当链表满的时候,就将链表尾部的数据丢弃。
- 3.利用链表和hashmap。当需要插入新的数据项的时候,如果新数据项在链表中存在(一般称为命中),则把该节点移到链表头部,如果不存在,则新建一个节点,放到链表头部,若缓存满了,则把链表最后一个节点删除即可。在访问数据的时候,如果数据项在链表中存在,则把该节点移到链表头部,否则返回-1。这样一来在链表尾部的节点就是最近最久未访问的数据项。
- 对于第一种方法,需要不停地维护数据项的访问时间戳,另外,在插入数据、删除数据以及访问数据时,时间复杂度都是O(n)。对于第二种方法,链表在定位数据的时候时间复杂度为O(n)。所以在一般使用第三种方式来是实现LRU算法。
http协议
一个HTTP请求报文由请求行(request line)、请求头部(header)、空行和请求数据4个部分组成
请求行
请求行由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔。
GET
常见的一种请求方式,当客户端要从服务器中读取文档时,当点击网页上的链接或者通过在浏览器的地址栏输入网址来浏览网页 的,使用的都是GET方式。GET方法要求服务器将URL定位的资源放在响应报文的数据部分,回送给客户端。使用GET方法时,请 求参数和对应的值附加在URL后面,利用一个问号(“?”)代表URL的结尾与请求参数的开始,传递参数长度受限制。例 如,/index.jsp?id=100&op=bind,这样通过GET方式传递的数据直接表示在地址中,所以我们可以把请求结果以链接的形式发 送给好友
POST
使用POST方法可以允许客户端给服务器提供信息较 多。POST方法将请求参数封装在HTTP请求数据中,以名称/值的形式出现,可以传输大量数据,这样POST方式对传送的数据大 小没有限制,而且也不会显示在URL中,POST方式请求行中不包含数据字符串,这些数据保存在”请求内容”部分,各数据之间也是使用”&”符号隔开。POST方 式大多用于页面的表单中。因为POST也能完成GET的功能,因此多数人在设计表单的时候一律都使用POST方式,其实这是一个 误区。
HEAD
HEAD就像GET,只不过服务端接受到HEAD请求后只返回响应头,而不会发送响应内容。当我们只需要查看某个页面的状态的时 候,使用HEAD是非常高效的,因为在传输的过程中省去了页面内容。
请求头部
- 请求头部由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔。
- 请求头部通知服务器有关于客户端请求的信息,典型的 请求头有:
- UserAgent:产生请求的浏览器类型。
- Accept:客户端可识别的内容类型列表。
- Host:请求的主机名,允许多个域名同处一个IP地址,即虚拟主机。
空行
后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不再有请求头。
请求数据
请求数据不在GET方法中使用,而是在POST方法中使用。POST方法适用于需要客户填写表单的场合。与请求数据相关的常使 用的请求头是ContentType和ContentLength。
HTTP相应报文
HTTP响应也由三个部分组成,分别是:状态行、消息响应头、响应正文。
状态码
- 1xx:指示信息表示请求已接收,继续处理。
- 2xx:成功表示请求已被成功接收、理解、接受。
- 3xx:重定向要完成请求必须进行更进一步的操作。
- 4xx:客户端错误请求有语法错误或请求无法实现。
- 5xx:服务器端错误服务器未能实现合法的请求。
常见状态代码、状态描述的说明如下
- 200 OK:客户端请求成功。
- 400 Bad Request:客户端请求有语法错误,不能被服务器所理解。
- 401 Unauthorized:请求未经授权,这个状态代码必须和WWWAuthenticate报头域一起使用。
- 403 Forbidden:服务器收到请求,但是拒绝提供服务。
- 404 Not Found:请求资源不存在,举个例子:输入了错误的URL。 500 Internal Server Error:服务器发生不可预期的错误。
- 503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常,举个例子:HTTP/1.1 200 OK(CRLF)。
GET和POST
- GET提交,请求的数据会附在URL之后(就是把数据放置在HTTP协议头<requestline>中),以?分割URL和传输数据,多个 参数用&连接;如果数 据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密,,GET提交的数据会在地址栏中显示出来,而POST提交,地址栏不会改变, POST提交:把提交的数据放置在是HTTP包的包体<request body>中。
- HTTP协议没有对传输的数据大小进行限制,HTTP协议规范也没有对URL长度进行限制。 而在实际开发中存在的限制 主要有:
- GET:特定浏览器和服务器对URL长度有限制,例如IE对URL长度的限制是2083字节(2K+35)。对于其他浏览器,如 Netscape、FireFox等,理论上没有长度限制,其限制取决于操作系统的支持。
- 因此对于GET提交时,传输数据就会受到URL长度的限制。
- POST:由于不是通过URL传值,理论上数据不受限。但实际各个WEB服务器会规定对post提交数据大小进行限制,Apache、 IIS6都有各自的配置。
- POST的安全性要比GET的安全性高。注意:这里所说的安全性和上面GET提到的“安全”不是同个概念。上面“安全”的含义仅仅 是不作数据修改,而这里安全的含义是真正的Security的含义,比如:通过GET提交数据,用户名和密码将明文出现在URL上,因 为(1)登录页面有可能被浏览器缓存, (2)其他人查看浏览器的历史纪录,那么别人就可以拿到你的账号和密码了,
数据类型
- 标量 :boolean (布尔型)integer (整型)float (浮点型, 也称作 double) string (字符串)
- 复合 :数组 对象
- 特殊 :NULL resource(资源)
常见的header头
- // 信息型状态码,提示目前为止一切正常,客户端应该继续请求, 如果已完成请求则忽略.
- header('HTTP/1.1 100 OK');
- //通知浏览器 页面不存在
- header('HTTP/1.1 404 Not Found');
- //资源被永久的重定向 301 ;302:临时重定向(该资源临时被改变位置)
- header('HTTP/1.1 301 Moved Permanently');
- //跳转到一个新的地址
- header('Location: http://php.itcast.cn/');
- //延迟转向也就是隔几秒跳转
- header('Refresh:10;url=http://php.itcast.cn/');
-
内容类型###
- //网页编码
- header('Content-Type: text/html;charset=utf-8');
- //纯文本格式
- header('Content-Type:text/plain');
- //JPG、JPEG
- header('Content-Type:image/jpeg');
- //ZIP文件
- header('Content-Type:application/zip');
- //PDF文件
- header('Content-Type:application/pdf');
- //音频文件
- header('Content-Type: ');
- //css文件
- header('Content-type:text/css');
-
声明一个下载的文件###
- header('Content-Type:application/octet-stream');
- header('Content-Disposition:attachment;filename="ITblog.zip"');
-
显示一个需要验证的登陆对话框###
- header('HTTP/1.1 401Unauthorized');
- header('WWW-Authenticate:Basic realm="TopSecret"');
魔术方法
- __autoload() 类文件自动加载函数
- __construct() 构造函数,PHP将在对象创建时调用这个方法
- __destruct() 析构函数,PHP将在对象被销毁前(即从内存中清除前)调用这个方法
- __call() 当所调用的成员方法不存在(或者没有权限)该类时调用,用于对错误后做一些操作或者提示信息
- __clone() 该函数在对象克隆时自动调用,其作用是对克隆的副本做一些初始化操作
- __get() 当所对象所调用的成员属性未声明或者级别为private或者protected等时,我们可以在这个函数里进行自己的一些操作
- __set() 当所对未声明或者级别为private或者protected等进行赋值时调用此函数,我们可以在这个函数里进行自己的一些操作
- __isset() 当对一个未声明或者访问级别受限的成员属性调用isset函数时调用此函数,共用户做一些操作
- __unset() 当对一个未声明或者访问级别受限的成员属性调用unset函数时调用此函数,共用户做一些操作
- __toString()函数 该函数在将对象引用作为字符串操作时自动调用,返回一个字符串
- __sleep()函数 该函数是在序列化时自动调用的,序列化这里可以理解成将信息写如文件中更长久保存
- __wakeup()函数 该魔术方法在反序列化的时候自动调用,为反序列化生成的对象做一些初始化操作
- __invoke()函数,当尝试以调用函数的方式调用一个对象时,__invoke 方法会被自动调用。
- _callStatic()函数,它的工作方式类似于 __call() 魔术方法,__callStatic() 是为了处理静态方法调用,
超全局变量
- $GLOBALS是PHP的一个超级全局变量组,在一个PHP脚本的全部作用域中都可以访问。是一个包含了全部变量的全局组合数组。变量的名字就是数组的键。
- $_SERVER是一个包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组。这个数组中的项目由 Web 服务器创建。不能保证每个服务器都提供全部项目;服务器可能会忽略一些,或者提供一些没有在这里列举出来的项目。
- $_REQUEST 用于收集HTML表单提交的数据。
- $_POST 被广泛应用于收集表单数据,在HTML form标签的指定该属性:"method="post"。
- $_GET 同样被广泛应用于收集表单数据,在HTML form标签的指定该属性:"method="get"。
- $_COOKIE 经由 HTTP Cookies 方法提交至脚本的变量
- HTTP_SESSION_VARS 数组。
- HTTP_POST_FILES 数组。
- HTTP_ENV_VARS 数组。
http 和 https 区别
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
hash取模算法
hash算法
分布式cahce系统中的一致性hash算法应该满足以下几个方面
平衡性(Balance)
哈希的结果能够尽可能分布到所有的缓冲中去,这样可以使得所有的缓冲空间都得到利用。
单调性(Monotonicity)
如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的缓冲区加入到系统中,那么哈希的结果应能够保证原有已分配的内容可以被映射到新的缓冲区中去,而不会被映射到旧的缓冲集合中的其他缓冲区。简单的哈希算法往往不能满足单调性的要求,如最简单的线性哈希:x = (ax + b) mod (P),在上式中,P表示全部缓冲的大小。不难看出,当缓冲大小发生变化时(从P1到P2),原来所有的哈希结果均会发生变化,从而不满足单调性的要求。哈希结果的变化意味着当缓冲空间发生变化时,所有的映射关系需要在系统内全部更新。而在P2P系统内,缓冲的变化等价于Peer加入或退出系统,这一情况在P2P系统中会频繁发生,因此会带来极大计算和传输负荷。单调性就是要求哈希算法能够应对这种情况。
分散性(Spread)
在分布式环境中,终端有可能看不到所有的缓冲,而是只能看到其中的一部分。当终端希望通过哈希过程将内容映射到缓冲上时,由于不同终端所见的缓冲范围有可能不同,从而导致哈希的结果不一致,最终的结果是相同的内容被不同的终端映射到不同的缓冲区中。这种情况显然是应该避免的,因为它导致相同内容被存储到不同缓冲中去,降低了系统存储的效率。分散性的定义就是上述情况发生的严重程度。好的哈希算法应能够尽量避免不一致的情况发生,也就是尽量降低分散性。
负载(Load)
负载问题实际上是从另一个角度看待分散性问题。既然不同的终端可能将相同的内容映射到不同的缓冲区中,那么对于一个特定的缓冲区而言,也可能被不同的用户映射为不同的内容。与分散性一样,这种情况也是应当避免的,因此好的哈希算法应能够尽量降低缓冲的负荷。
平滑性(Smoothness)
平滑性是指缓存服务器的数目平滑改变和缓存对象的平滑改变是一致的。
hash取模算法
常用的算法是对hash结果取余数 (hash() mod N):对机器编号从0到N-1,按照自定义的hash()算法,对每个请求的hash()值按N取模,得到余数i,然后将请求分发到编号为i的机器。但这样的算法方法存在致命问题,如果某一台机器宕机,那么应该落在该机器的请求就无法得到正确的处理,这时需要将当掉的服务器从算法从去除,此时候会有(N-1)/N的服务器的缓存数据需要重新进行计算;
为何是 (N-1)/N 呢
- 比如有 3 台机器,hash值 1-6 在这3台上的分布就是:
- host 1: 1 4
- host 2: 2 5
- host 3: 3 6
- 如果挂掉一台,只剩两台,模数取 2 ,那么分布情况就变成:
- host 1: 1 3 5
- host 2: 2 4 6
- 可以看到,还在数据位置不变的只有2个: 1,2,位置发生改变的有4个,占共6个数据的比率是 4/6 = 2/3。
虚拟节点
- 对于hash取模算法,当某个节点的服务器坏了,算有压力将转到下个节点的服务器。那我们考虑是否能够将压力转到其他节点。
- 虚拟节点即:N个真实节点,把每个真实节点映射成M个虚拟节点, 再把M* N个虚拟节点,
- 散列在圆环上. 各真实节点对应的虚拟节点相互交错分布,这样,某真实节点down后,则把其影响平均分担到其他所有节点上。
访问方法:
如果有一个写入缓存的请求,其中Key值为K,计算器hash值Hash(K), Hash(K) 对应于环中的某一个点,如果该点对应没有映射到具体的某一个机器节点,那么顺时针查找,直到第一次找到有映射机器的节点,该节点就是确定的目标节点,如果超过了2^32仍然找不到节点,则命中第一个机器节点。
一致性哈希算法
一种特殊的哈希算法,目前主要应用于分布式缓存当中,可以有效地解决分布式存储结构下动态增加和删除节点所带来的问题。
- 一致性Hash算法是对232取模,232个点组成的圆环称为Hash环。根据服务节点的IP或者机器名称进行哈希,就能确定每台机器就能确定其在哈希环上的位置;
- 将数据key使用相同的函数Hash计算出哈希值,并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器。
- 添加、删除节点的时候,只影响相邻一个节点的数据,其他节点的数据不影响。具有较好的扩展性和容错性。
- 为了防止数据分布不均匀,可以应用虚拟节点来映射物理节点。
hash槽
Redis准备了16384个hash槽,类似于Memcached Hash环上的一个个位置。 这16384个hash槽被分配给不同节点,存放数据时,根据数据的key计算出所在的槽,再根据槽找到对应的机器。hash函数为:CRC16(key) % 16384。
为什么是16384?
我们需要维护节点和槽之间的映射关系,每个节点需要知道自己有哪些槽,并且需要在结点之间传递这个消息。为了节省存储空间,每个节点用一个Bitmap来存放其对应的槽: 2k = 210248 = 16384,也就是说,每个结点用2k的内存空间,总共16384个比特位,就可以存储该结点对应了哪些槽。然后这2k的信息,通过Gossip协议,在结点之间传递。
php远程获取文件
第一种:file_get_contents
$url = '![](file:///C:\Users\ASUS\AppData\Roaming\Tencent\QQ\Temp\%W@GJ$ACOF(TYDYECOKVDYB.png)http://www.xxx.com/';
$contents = file_get_contents($url)
curl
** 第二种使用 curl **
$url = “![](file:///C:\Users\ASUS\AppData\Roaming\Tencent\QQ\Temp\%W@GJ$ACOF(TYDYECOKVDYB.png)http://www.xxx.com/”;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);\
$contents = curl_exec($ch);
第三种
3.fopen->fread->fclose
$handle = fopen (“![](file:///C:\Users\ASUS\AppData\Roaming\Tencent\QQ\Temp\%W@GJ$ACOF(TYDYECOKVDYB.png)http://www.xxx.com/”, “rb”);
$data = fread($handle, 8192)
一般我们使用 curl 来进行 文章的抓取 他可以设置 超时时间 比较方便
怎么解决请求被劫持的问题
推荐用https,充分测试无问题以后在服务器端配置HSTS头,但即使这样也还不能解决首次访问时的劫持问题,不过已经能解决绝大部分的问题了。如果是个人网站,建议直接用sha2的证书,sha1的证书已经不安全了,双证书费用和维护成本都不低,何况第三方浏览器现在是流量的大头
用户输入url到页面显示经历了哪些
**通过DNS找对应的IP **
- 找浏览器缓存,浏览器会保存一段时间你之前访问过的一些网址的DNS信息
- 通过dns 找 域 名对应ip 本地的 host 通过dns 找 域名对应ip
- 接着会发送一个请求到路由器上,然后路由器在自己的路由器缓存上查找记录,路由器一 般也存有DNS信息。
- 通过dns 找 域名对应ip 你的ISP的DNS服务器会将请求发向根域名服务器进行搜通过dns 找 域名对应ip
**通过IP 向对应的web服务器发送请求 **
浏览器终于得到了IP以后,浏览器接着给这个IP的服务器发送了一个http请求,方式为get,例如访问nbut.cn
**服务器接受到请求后,如果是nginx 通过nginx的location匹配 后缀是.php的文件, 然后如果是,则将这个请求转发到127.0.0.1:9000的个服务,而9000 这个服务是PHP, 把请求交给php来进行处理,php处理完毕,把处理的数据发送给nginx ,nginx把数据再 相应,并发送给浏览器 **
服务器收到浏览器的请求以后(其实是WEB服务器接收到了这个请求,WEB服务器有iis、 apache等 会解析这个请求(读请求头),然后生成一个响应头和具体响应内容 如果是个静态页面,那么基本上到这一步就没了
页面还有其他资源(css img js ) 继续重复执行
主页(index)页面框架传送过来以后,浏览器还要继续向服务器发送请求,请求的内容是 主页里面包含的一些资源,如图片,视频,css样式等等
php 相关
cgi ,fastcgi,php-fpm 区别
cgi
- CGI的英文是(COMMON GATEWAY INTERFACE)公共网关接口,它的作用就是帮助服务器与语言通信,这里就是nginx和php进行通信,因为nginx和php的语言不通,因此需要一个沟通转换的过程,而CGI就是这个沟通的协议。
- nginx服务器在接受到浏览器传递过来的数据后,如果请求的是静态的页面或者图片等无需动态处理的则会直接根据请求的url找到其位置然后返回给浏览器,这里无需php参与,但是如果是一个动态的页面请求,这个时候nginx就必须与php通信,这个时候就会需要用到cgi协议,将请求数据转换成php能理解的信息,然后php根据这些信息返回的信息也要通过cgi协议转换成nginx可以理解的信息,最后nginx接到这些信息再返回给浏览器。
fast-cgi
- 传统的cgi协议在每次连接请求时,会开启一个进程进行处理,处理完毕会关闭该进程,因此下次连接,又要再次开启一个进程进行处理,因此有多少个连接就有多少个cgi进程,这也就是为什么传统的cgi会显得缓慢的原因,因此过多的进程会消耗资源和内存。
- 而fast-cgi每次处理完请求后,不会kill掉这个进程,而是保留这个进程,使这个进程可以一次处理多个请求。这样每次就不用重新fork一个进程了,大大提高效率。
php-cgi
php-cgi是php提供给web serve也就是http前端服务器的cgi协议接口程序,当每次接到http前端服务器的请求都会开启一个php-cgi进程进行处理,而且开启的php-cgi的过程中会先要重载配置,数据结构以及初始化运行环境,如果更新了php配置,那么就需要重启php-cgi才能生效,例如phpstudy就是这种情况。
php-fpm
- php-fpm是php提供给web serve也就是http前端服务器的fastcgi协议接口程序,它不会像php-cgi一样每次连接都会重新开启一个进程,处理完请求又关闭这个进程,而是允许一个进程对多个连接进行处理,而不会立即关闭这个进程,而是会接着处理下一个连接。它可以说是php-cgi的一个管理程序,是对php-cgi的改进。
- php-fpm会开启多个php-cgi程序,并且php-fpm常驻内存,每次web serve服务器发送连接过来的时候,php-fpm将连接信息分配给下面其中的一个子程序php-cgi进行处理,处理完毕这个php-cgi并不会关闭,而是继续等待下一个连接,这也是fast-cgi加速的原理,但是由于php-fpm是多进程的,而一个php-cgi基本消耗7-25M内存,因此如果连接过多就会导致内存消耗过大,引发一些问题,例如nginx里的502错误。
- 同时php-fpm还附带一些其他的功能:
- 例如平滑过渡配置更改,普通的php-cgi在每次更改配置后,需要重新启动才能初始化新的配置,而php-fpm是不需要,php-fpm分将新的连接发送给新的子程序php-cgi,这个时候加载的是新的配置,而原先正在运行的php-cgi还是使用的原先的配置,等到这个连接后下一次连接的时候会使用新的配置初始化,这就是平滑过渡。
参考链接:https://blog.csdn.net/belen_xue/article/details/65950658
PHP5 跟php7的区别
PHP7.0 号称是性能提升上革命性的一个版本。面对 Facebook 家的 HHVM 引擎带来的压力,开发团队重写了底层的 Zend Engine,名为 Zend Engine 2。
底层内核解析
PHP7 中最重要的改变就是 zval 不再单独从堆上分配内存并且不自己存储引用计数。需要使用 zval 指针的复杂类型(比如字符串、数组和对象)会自己存储引用计数。这样就可以有更少的内存分配操作、更少的间接指针使用以及更少的内存分配。在PHP7中的zval, 已经变成了一个值指针, 它要么保存着原始值, 要么保存着指向一个保存原始值的指针. 也就是说现在的zval相当于PHP5的时候的zval * . 只不过相比于zval * , 直接存储zval, 我们可以省掉一次指针解引用, 从而提高缓存友好性.
参考链接:https://www.jb51.net/article/76732.htm
PHP7 为什么比 PHP5 性能提升了
1、变量存储字节减小,减少内存占用,提升变量操作速度
2、改善数组结构,数组元素和hash映射表被分配在同一块内存里,降低了内存占用、提升了 cpu 缓存命中率
3、改进了函数的调用机制,通过优化参数传递的环节,减少了一些指令,提高执行效率
安全
函数修改
- preg_replace()不再支持/e修饰符,,同时官方给了我们一个新的函数preg_replace_callback
- create_function()被废弃,实际上它是通过执行eval实现的。
- mysql_* 系列全员移除,如果你要在PHP7上面用老版本的mysql_* 系列函数需要你自己去额外装了,官方不在自带,现在官方推荐的是mysqli或者pdo_mysql。
- unserialize()增加一个可选白名单参数,其实就是一个白名单,如果反序列数据里面的类名不在这个白名单内,就会报错。
- assert() 默认不在可以执行代码
语法修改
- foreach不再改变内部数组指针
- 8进制字符容错率降低,在php5版本,如果一个八进制字符如果含有无效数字,该无效数字将被静默删节。在php7里面会触发一个解析错误。
- 十六进制字符串不再被认为是数字
- 移除了 ASP 和 script PHP 标签
- 超大浮点数类型转换截断,将浮点数转换为整数的时候,如果浮点数值太大,导致无法以整数表达的情况下, 在PHP5的版本中,转换会直接将整数截断,并不会引发错误。 在PHP7中,会报错。
参考链接:https://www.freebuf.com/articles/web/197013.html
总体
- 性能提升:PHP7比PHP5.0性能提升了两倍。
- 全面一致的64位支持。
- 以前的许多致命错误,现在改成[抛出异常]。
- PHP 7.0比PHP5.0移除了一些老的不在支持的SAPI([服务器端]应用编程端口)和扩展。
- .PHP 7.0比PHP5.0新增了空接合操作符。
- PHP 7.0比PHP5.0新增加了结合比较运算符。
- PHP 7.0比PHP5.0新增加了函数的返回类型声明。
- PHP 7.0比PHP5.0新增加了标量类型声明。
- PHP 7.0比PHP5.0新增加匿名类。
多进程同时读写一个文件
- PHP是支持进程的而不支持多线程(这个先搞清楚了),如果是对于文件操作,其实你只需要给文件加锁就能解决,不需要其它操作,PHP的flock已经帮你搞定了。
- 用flock在写文件前先锁上,等写完后解锁,这样就实现了多线程同时读写一个文件避免冲突。
流程
- flock参数说明:file 必需,规定要锁定或释放的已打开的文件,lock 必需。规定要使用哪种锁定类型。block 可选。若设置为 1 或 true,则当进行锁定时阻挡其他进程。
- LOCK_SH 要取得共享锁定(读取的程序)
- LOCK_EX 要取得独占锁定(写入的程序)
- LOCK_UN 要释放锁定(无论共享或独占)
- LOCK_NB 如果不希望 flock() 在锁定时堵塞
在PHP中,flock似乎工作的不是那么好!在多并发情况下,似乎是经常独占资源,不即时释放,或者是根本不释放,造成死锁,从而使服务器的cpu占用很高,甚至有时候会让服务器彻底死掉。好所以使用flock之前,一定要慎重考虑。
解决方案
- 对文件进行加锁时,设置一个超时时间,超时设置为1ms,如果这里时间内没有获得锁,就反复获得,直接获得到对文件操作权为止,当然。如果超时限制已到,就必需马上退出,让出锁让其它进程来进行操作。
- 不使用flock函数,借用临时文件来解决读写冲突的问题
- 将需要更新的文件考虑一份到我们的临时文件目录,将文件最后修改时间保存到一个变量,并为这个临时文件取一个随机的,不容易重复的文件名。
- 当对这个临时文件进行更新后,再检测原文件的最后更新时间和先前所保存的时间是否一致。
- 如果最后一次修改时间一致,就将所修改的临时文件重命名到原文件,为了确保文件状态同步更新,所以需要清除一下文件状态。
- 但是,如果最后一次修改时间和先前所保存的一致,这说明在这期间,原文件已经被修改过,这时,需要把临时文件删除,然后返回false,说明文件这时有其它进程在进行操作。
- 对操作的文件进行随机读写,以降低并发的可能性。
- 先前需要定义一个随机空间,空间越大,并发的的可能性就越小,这里假设随机读写空间为[1-500],那么我们的日志文件的分布就为log1到log500不等。每一次用户访问,都将数据随机写到log1log500之间的任一文件。在同一时刻,有2个进程进行记录日志,A进程可能是更新的log32文件,而B进程呢?则此时更新的可能就为log399.要知道,如果要让B进程也操作log32,概率基本上为1/500,差不多约等于零。在需要对访问日志进行分析时,这里我们只需要先将这些日志合并,再进行分析即可。使用这种方案来记录日志的一个好处时,进程操作排队的可能性比较小,可以使进程很迅速的完成每一次操作。
- 将所有要操作的进程放入一个队列中。
- 队列中的每一个排除的进程相当于第一个具体的操作,所以第一次我们的服务只需要从队列中取得相当于具体操作事项就可以了,如果这里还有大量的文件操作进程,没关系,排到我们的队列后面即可,只要愿意排,队列的多长都没关系。
框架方面
tp框架
优点
TP框架是我们中国人自己开发的框架,各种资料比较齐全,国内用的比较多,比较简单
和方便,而且是免费开源的
特性
- 多表查询非常方便,在 model 中几句代码就可以完成对多表的关联操作
- 融合了 smarty 模板,使前后台分离
- 支持多种缓存技术,尤其对 memcache 技术支持非常好
- 命名规范,模型,视图,控制器严格遵循命名规则,通过命名一一对应
- 支持多种 url 模式
- 内置 ajax 返回方法,包括 xml,json,html 等
- 支持应用扩展,类库扩展,驱动扩展
大写字母
U:对 url 的组装 A:内部实例化控制器 S:缓存处理 R:调用某个控制器的操作方法 D:实例化
自定义模型类 M:实例化基础模型类 I:获取参数 L:设置或者获取当前语言 C:设置或获取,
保存配置
laravel框架
简介
laravel框架的设计思想比较先进,非常适合应用各种开发模式,作为一个框架,它为你
准备好了一切,composer是php的未来,没有 composer,php肯定要走向没落
laravel框架最大的特点和优秀之处就是集合了php比较新的特点,以及各种各样的设计
模式,Ioc模式,依赖注入等.
特点
1.强大的rest router:用简单的回调函数就可以调用,快速绑定controller和router
2.artisan:命令行工具,很多手动的工作都自动化
3.可继承的模板,简化 view的开发和管理
4.blade模板:渲染速度更快
5.ORM操作数据库
6.migration:管理数据库和版本控制
7.测试功能也很强大
8.composer也是亮点
laravel框架引入了门面,依赖注入,Ioc模式,以及各种各样的设计模式等
composer
简介
composer依赖管理工具,且实现了自动加载。开发人员只需要几个命令行,就能获取其他开发者的包,PHP开发工作因此变得如同堆积木,可以根据业务的需求,快速方便地拆解组合代码。它不是一个包管理器。是的,它涉及 "packages" 和 "libraries",但它在每个项目的基础上进行管理,在你项目的某个目录中(例如 vendor)进行安装。默认情况下它不会在全局安装任何东西。因此,这仅仅是一个依赖管理。
命令
- composer install 依据当前目录下的 composer.lock(锁文件) 或 composer.json 文件,所定义的依赖关系,安装依赖包。
- composer update 更新依赖版本,如果你修改了 composer.json 中的依赖关系,想让 composer 按照composer.json 文件中的定义执行更新操作,就用 update 命令。
- composer require require 命令一般用来安装新的依赖包,并将依赖写入当前目录的 composer.json 文件中。如果 composer.json 文件中,添加或改变了依赖,修改后的依赖关系将被安装或者更新。
- create-project 你可以使用 create-project 从现有的包中创建一个新的项目。它相当于执行了 git clone 命令后,将这个包的依赖安装到它自己的 vendor 目录。
设计模式
创建型
在软件工程中,创建型设计模式是处理对象创建机制的设计模式,试图以适当的方式来创建对象。对象创建的基本形式可能会带来设计问题,亦或增加了设计的复杂度。创建型设计模式通过控制这个对象的创建方式来解决此问题。
抽象工厂模式
在不指定具体类的情况下创建一系列相关或依赖对象。 通常创建的类都实现相同的接口。 抽象工厂的客户并不关心这些对象是如何创建的,它只是知道它们是如何一起运行的。
建造者模式
- 建造者是创建一个复杂对象的一部分接口。
- 有时候,如果建造者对他所创建的东西拥有较好的知识储备,这个接口就可能成为一个有默认方法的抽象类(又称为适配器)。
- 如果对象有复杂的继承树,那么对于建造者来说,有一个复杂继承树也是符合逻辑的。
- 注意:建造者通常有一个「流式接口」,例如 PHPUnit 模拟生成器。
工厂方法模式
- 对比简单工厂模式的优点是,您可以将其子类用不同的方法来创建一个对象。
- 举一个简单的例子,这个抽象类可能只是一个接口。
- 这种模式是「真正」的设计模式, 因为他实现了 S.O.L.I.D 原则中「D」的 「依赖倒置」。
- 这意味着工厂方法模式取决于抽象类,而不是具体的类。 这是与简单工厂模式和静态工厂模式相比的优势。
多例模式
对象池模式
- 对象池模式是一种提前准备了一组已经初始化了的对象『池』而不是按需创建或者销毁的创建型设计模式。对象池的客户端会向对象池中请求一个对象,然后使用这个返回的对象执行相关操作。当客户端使用完毕,它将把这个特定类型的工厂对象返回给对象池,而不是销毁掉这个对象。
- 在初始化实例成本高,实例化率高,可用实例不足的情况下,对象池可以极大地提升性能。在创建对象(尤其是通过网络)时间花销不确定的情况下,通过对象池在可期时间内就可以获得所需的对象。
- 无论如何,对象池模式在需要耗时创建对象方面,例如创建数据库连接,套接字连接,线程和大型图形对象(比方字体或位图等),使用起来都是大有裨益的。在某些情况下,简单的对象池(无外部资源,只占内存)可能效率不高,甚至会有损性能。
原型模式
相比正常创建一个对象 (new Foo () ),首先创建一个原型,然后克隆它会更节省开销。
简单工厂模式
- 简单工厂模式是一个精简版的工厂模式。
- 它与静态工厂模式最大的区别是它不是『静态』的。因为非静态,所以你可以拥有多个不同参数的工厂,你可以为其创建子类。甚至可以模拟(Mock)他,这对编写可测试的代码来讲至关重要。
单例模式
单例模式被公认为是 反面模式,为了获得更好的可测试性和可维护性,请使用『依赖注入模式』。主要为了在应用程序调用的时候,只能获得一个对象实例。主要包括:数据库的连接,日志的使用等。
静态工厂模式
与抽象工厂模式类似,此模式用于创建一系列相关或相互依赖的对象。 『静态工厂模式』与『抽象工厂模式』的区别在于,只使用一个静态方法来创建所有类型对象, 此方法通常被命名为
factory
或build
。
结构型
在软件工程中,结构型设计模式是通过识别实体之间关系来简化设计的设计模式。
行为型
在软件工程中,行为设计模式是识别对象之间的通用通信模式并实现这些模式的设计模式。 通过这样做,这些模式增加了执行此通信的灵活性。
生命周期
php的生命周期
- 模块初始化阶段(Module init):即调用每个拓展源码中的的PHP_MINIT_FUNCTION中的方法初始化模块,进行一些模块所需变量的申请,内存分配等。
- 请求初始化阶段(Request init):即接受到客户端的请求后调用每个拓展的PHP_RINIT_FUNCTION中的方法,初始化PHP脚本的执行环境。
- 执行该PHP脚本。
- 请求结束(Request Shutdown):这时候调用每个拓展的PHP_RSHUTDOWN_FUNCTION方法清理请求现场,并且ZE开始回收变量和内存
- 关闭模块(Module shutdown):Web服务器退出或者命令行脚本执行完毕退出会调用拓展源码中的PHP_MSHUTDOWN_FUNCTION 方法
laravel的生命周期
- 加载项目依赖,注册加载composer自动生成的class loader,也就是加载初始化第三方依赖。
- 创建应用实例,生成容器 Container,并向容器注册核心组件,是从 bootstrap/app.php 脚本获取 Laravel 应用实例,并且绑定内核服务容器,它是HTTP 请求的运行环境的不同,将请求发送至相应的内核: HTTP 内核 或 Console 内核。
- 接收请求并响应,请求被发送到 HTTP 内核或 Console 内核,这取决于进入应用的请求类型。HTTP 内核继承自 Illuminate\Foundation\Http\Kernel 类,该类定义了一个 bootstrappers 数组,这个数组中的类在请求被执行前运行,这些 bootstrappers 配置了错误处理、日志、检测应用环境以及其它在请求被处理前需要执行的任务。HTTP 内核还定义了一系列所有请求在处理前需要经过的 HTTP 中间件,这些中间件处理 HTTP 会话的读写、判断应用是否处于维护模式、验证 CSRF 令牌等等。
- 发送请求,在Laravel基础的服务启动之后,把请求传递给路由了。路由器将会分发请求到路由或控制器,同时运行所有路由指定的中间件。传递给路由是通过 Pipeline(管道)来传递的,在传递给路由之前所有请求都要经过app\Http\Kernel.php中的$middleware数组,也就是中间件,默认只有一个全局中间件,用来检测你的网站是否暂时关闭。所有请求都要经过,你也可以添加自己的全局中间件。然后遍历所有注册的路由,找到最先符合的第一个路由,经过它的路由中间件,进入到控制器或者闭包函数,执行你的具体逻辑代码,把那些不符合或者恶意的的请求已被Laravel隔离在外。
基础组件 - 日志
- Laravel 提供了强大的日志服务来记录日志信息到文件、系统错误日志、甚至是 Slack 以便通知整个团队。在日志引擎之下,Laravel 集成了 Monolog 日志库以便提供各种功能强大的日志处理器,从而允许你通过它们来定制自己应用的日志处理。
- 应用日志系统的所有配置都存放在配置文件
config/logging.php
中,该文件允许你配置应用的日志通道,因此需要查看每个可用通道及其配置项,默认情况下,Laravel 使用 stack 通道来记录日志信息,stack 通道被用于聚合多个日志通道到单个通道
配置通道名称
默认情况下,Monolog 通过与当前环境匹配的「通道名称」实例化,例如
production
或local
,要改变这个值,添加name
项到通道配置
有效通道驱动列表
stack
用于创建「多通道」通道的聚合器single
基于单文件/路径的日志通道(StreamHandler
)daily
基于RotatingFileHandler
的 Monolog 驱动,以天为维度对日志进行分隔slack
基于SlackWebhookHandler
的 Monolog 驱动syslog
基于SyslogHandler
的 Monolog 驱动errorlog
基于ErrorLogHandler
的 Monolog 驱动monolog
Monolog 改成驱动,可以使用所有支持的 Monolog 处理器custom
调用指定改成创建通道的驱动
配置 Single 和 Daily 通道
single
和daily
通道有三个可选配置项:bubble
、permission
和locking
。bubble
表示消息在被处理后是否冒泡到其它通道 ,默认为true
permission
日志文件权限,默认为644
locking
在日志文件写入前尝试锁定它,默认为false
配置 Slack 通道
slack
通道需要一个 url
配置项,这个 URL 需要和你配置的 Slack 团队[请求 URL]相匹配。
构建日志堆栈
stack
驱动允许你将多个通道合并到单个日志通道,stack 通道通过 channels 项将聚合了其他两个通道:syslog 和 slack。因此,记录日志信息时,这两个通道都有机会记录信息。
参考链接:https://laravelacademy.org/post/19467.html
面向对象oop
是什么
oop是面向对象编程,面向对象编程是一种计算机编程架构,OOP 的一条基本原则是
计算机程序是由单个能够起到子程序作用的单元或对象组合而成。
**三大特点 **
1、封装性:也称为信息隐藏,就是将一个类的使用和实现分开,只保留部分接口和方
法与外部联系,或者说只公开了一些供开发人员使用的方法。于是开发人员只 需要关
注这个类如何使用,而不用去关心其具体的实现过程,这样就能实现MVC分工合作,
也能有效避免程序间相互依赖,实现代码模块间松藕合。
2、继承性:就是子类自动继承其父级类中的属性和方法,并可以添加新的属性和方法
或者对部分属性和方法进行重写。继承增加了代码的可重用性。PHP只支持单继承,也
就是说一个子类只能有一个父类。
3、多态性:子类继承了来自父级类中的属性和方法,并对其中部分方法进行重写。于
是多个子类中虽然都具有同一个方法,但是这些子类实例化的对象调用这些相同的方法
后却可以获得完全不同的结果,这种技术就是多态性。多态性增强了软件的灵活性。
设计模式的五大原则
- 单一职责原则 单一职责原则可以看做是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因
- 开发封闭原则 开放-封闭原则是面向对象设计的核心所在。遵循这个原则可以带来面向对象技术所声称的巨大好处,也就是可维护,可扩展,可复用,灵活性好。
- 接口隔离原则 通俗点说,不要强迫客户使用它们不用的方法,如果强迫用户使用它们不使用的方法,那么这些客户就会面临由于这些不使用的方法的改变所带来的改变。
- 依赖倒置原则 依赖倒置原则其实可以说是面向对象设计的标志,用哪种语言来编写程序不重要,如果编写时考虑的都是如何针对抽象编程而不是针对细节编程,即程序中所有的依赖关系都是终止于抽象类或者接口,那就是面向对象的设计,反之那就是过程化的设计了。
- 里氏替换原则 任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
好处
1、易维护 采用面向对象思想设计的结构,可读性高,由于继承的存在,即使改变需求,那么维护
也只是在局部模块,所以维护起来是非常方便和较低成本的。
2、质量高 在设计时,可重用现有的,在以前的项目的领域中已被测试过的类使系统满足业务需求
并具有较高的质量。
3、效率高 在软件开发时,根据设计的需要对现实世界的事物进行抽象,产生类。使用这样的方法
解决问题,接近于日常生活和自然的思考方式,势必提高软件开发的效率和质量。
4、易扩展 由于继承、封装、多态的特性,自然设计出高内聚、低耦合的系统结构,使得系统更灵
活、更容易扩展,而且成本较低。
smarty
- smarty是用php写出来的模板引擎,也是目前业界最著名的php模板引擎之一 ,它分离了逻辑代码和外在的显示,提供了一种易于管理和使用的方法,用来将混杂的php
- 逻辑代码与html代码进行分离,smarty是php中最著名的引擎框架之一,我们公司使用的是TP框架,已经封装好了smarty模板,所以没有单独使用过
- smarty是个模板引擎,最显著的地方就是有可以把模板缓存起来。一般模板来说,都是做一个静态页面,然后在里面把一些动态的部分用一切分隔符切开,然后在PHP里打开这个模板文件,把分隔符里面的值替换掉,然后输出来,你可以看下PHPLib里面的template部分。
而smarty设定了缓存参数以后,第一次运行时候会把模板打开,在php替换里面值的
时候把读取的html和php部分重新生成一个临时的php文件,这样就省去了每次打
开都重新读取html了。如果修改了模板,只要重新刷下就行了。
socket,tcp,http三者之间的区别和原理
不同的TCP/IP和其他的协议在最初OSI模型中的位置
- | 7 | 应用层 :HTTP、SMTP、SNMP、FTP、Telnet、SIP、SSH、NFS、RTSP、XMPP、Whois、ENRP
- | 6 | 表示层:XDR、ASN.1、SMB、AFP、NCP
- | 5 | 会话层 :ASAP、TLS、SSH、ISO 8327 / CCITT X.225、RPC、NetBIOS、ASP、Winsock、BSD sockets
- | 4 | 传输层 :TCP、UDP、RTP、SCTP、SPX、ATP、IL
- | 3 | 网络层 : IP、ICMP、IGMP、IPX、BGP、OSPF、RIP、IGRP、EIGRP、ARP、RARP、 X.25
- | 2 | 数据链路层 :以太网、令牌环、HDLC、帧中继、ISDN、ATM、IEEE 802.11、FDDI、PPP
- | 1 | 物理层 :线路、无线电、光纤、信鸽
1、TCP/IP连接
TCP协议可以对上层网络提供接口,使上层网络数据的传输建立在“无差别”的网络之上。
- 建立起一个TCP连接需要经过三次握手
- 第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
- 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
- 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手
- 握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP连接都将被一直保持下去。断开连接时服务器和客户端均可以主动发起断开TCP连接的请求,断开过程需要经过“四次握手”(过程就不细写了,就是服务器和客户端交互,最终确定断开).
2、HTTP连接
HTTP协议即超文本传送协议(Hypertext Transfer Protocol ),是Web联网的基础,也是手机联网常用的协议之一,HTTP协议是建立在TCP协议之上的一种应用。
- HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。
- 1)在HTTP 1.0中,客户端的每次请求都要求建立一次单独的连接,在处理完本次请求后,就自动释放连接。
- 2)在HTTP 1.1中则可以在一次连接中处理多个请求,并且多个请求可以重叠进行,不需要等待一个请求结束后再发送下一个请求。
- 由于HTTP在每次请求结束后都会主动释放连接,因此HTTP连接是一种“短连接”,要保持客户端程序的在线状态,需要不断地向服务器发起连接请求。通常的做法是即时不需要获得任何数据,客户端也保持每隔一段固定的时间向服务器发送一次“保持连接”的请求,服务器在收到该请求后对客户端进行回复,表明知道客户端“在线”。若服务器长时间无法收到客户端的请求,则认为客户端“下线”,若客户端长时间无法收到服务器的回复,则认为网络已经断开。
3、SOCKET原理
套接字(socket)概念
- 套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
- 应用层通过传输层进行数据通信时,TCP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应用层可以和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。
建立socket连接
- 建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket 。
- 套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。
- 服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。
- 客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
- 连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
4、SOCKET连接与TCP/IP连接
- 建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。
- socket则是对TCP/IP协议的封装和应用(程序员层面上)。也可以说,TPC/IP协议是传输层协议,主要解决数据 如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。关于TCP/IP和HTTP协议的关系,网络有一段比较容易理解的介绍:
- “我们在传输数据时,可以只使用(传输层)TCP/IP协议,但是那样的话,如果没有应用层,便无法识别数据内容,如果想要使传输的数据有意义,则必须使用到应用层协议有很多,比如HTTP、FTP、TELNET等,也可以自己定义应用层协议。WEB使用HTTP协议作应用层协议,以封装HTTP文本信息,然后使用TCP/IP做传输层协议将它发到网络上。”
- 我们平时说的最多的socket是什么呢,实际上socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。 实际上,Socket跟TCP/IP协议没有必然的联系。Socket编程接口在设计的时候,就希望也能适应其他的网络协议。所以说,Socket的出现,只是使得程序员更方便地使用而已,是对TCP/IP协议的抽象,从而形成了我们知道的一些最基本的函数接口,比如create、listen、connect、accept、send、read和write等等。
- “TCP/IP只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口。这个就像操作系统会提供标准的编程接口,比如win32编程接口一样,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口。”
- 实际上,传输层的TCP是基于网络层的IP协议的,而应用层的HTTP协议又是基于传输层的TCP协议的,而Socket本身不算是协议,就像上面所说,它只是提供了一个针对TCP或者UDP编程的接口。socket是对端口通信开发的工具,它要更底层一些
5、Socket连接与HTTP连接
- 由于通常情况下Socket连接就是TCP连接,因此Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开。但在实际网络应用中,客户端到服务器之间的通信往往需要穿越多个中间节点,例如路由器、网关、防火墙等,大部分防火墙默认会关闭长时间处于非活跃状态的连接而导致 Socket 连接断连,因此需要通过轮询告诉网络,该连接处于活跃状态。
- 而HTTP连接使用的是“请求—响应”的方式,不仅在请求时需要先建立连接,而且需要客户端向服务器发出请求后,服务器端才能回复数据。
- 很多情况下,需要服务器端主动向客户端推送数据,保持客户端与服务器数据的实时与同步。此时若双方建立的是Socket连接,服务器就可以直接将数据传送给客户端;若双方建立的是HTTP连接,则服务器需要等到客户端发送一次请求后才能将数据传回给客户端,因此,客户端定时向服务器端发送连接请求,不仅可以保持在线,同时也是在“询问”服务器是否有新的数据,如果有就将数据传给客户端。
- http协议是应用层的协义
- 有个比较形象的描述:HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。
- 两个计算机之间的交流无非是两个端口之间的数据通信,具体的数据会以什么样的形式展现是以不同的应用层协议来定义的如HTTP,FTP...
vue
Vue单页网页路由
什么是单页Web应用
单页Web应用(single page web application,SPA),就是只有一张Web页面的应用。单页应用程序 (SPA) 是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。^ [1]^ 浏览器一开始会加载必需的HTML、CSS和JavaScript,所有的操作都在这张页面上完成,都由JavaScript来控制。因此,对单页应用来说模块化的开发和设计显得相当重要。
通常spa前端路由实现有两种方式
window.history
- window.history 对象包含浏览器的历史,window.history 对象在编写时可不使用 window 这个前缀。history是实现SPA前端路由是一种主流方法,它有几个原始方法
- history.back() - 与在浏览器点击后退按钮相同
- history.forward() - 与在浏览器中点击按钮向前相同
- history.go(n) - 接受一个整数作为参数,移动到该整数指定的页面,比如go(1)相当于forward(),go(-1)相当于back(),go(0)相当于刷新当前页面
- 注意:如果移动的位置超出了访问历史的边界,以上三个方法并不报错,而是静默失败
- 在HTML5,history对象提出了 pushState() 方法和 replaceState() 方法,这两个方法可以用来向历史栈中添加数据,就好像 url 变化了一样,这样就可以很好的模拟浏览历史和前进后退了,现在的前端路由也是基于这个原理实现的
- history.pushState(stateObj, title, url) 方法向历史栈中写入数据,其第一个参数是要写入的数据对象(不大于640kB),第二个参数是页面的 title, 第三个参数是 url (相对路径)。pushState方法不会触发页面刷新,只是导致history对象发生变化,地址栏会有反应,只有当触发前进后退等事件(back()和forward()等)时浏览器才会刷新
- history.replaceState(stateObj, title, url) 和pushState的区别就在于它不是写入而是替换修改浏览历史中当前纪录,其余和 pushState一模一样
location.hash
- hash模式:在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取;
- 特点:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无用,hash不会重加载页面。
- hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 [http://www.xxx.com],因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。
Vue的MVVM模式
- MVVM是Model-View-ViewModel的简写。即模型-视图-视图模型。【模型】指的是后端传递的数据。【视图】指的是所看到的页面。【视图模型】mvvm模式的核心,它是连接view和model的桥梁。
- 它有两个方向:
- 一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。
- 二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。这两个方向都实现的,我们称之为数据的双向绑定。
- Vue就是基于MVVM模式实现的一套框架,在vue中:Model:指的是js中的数据,如对象,数组等等。View:指的是页面视图viewModel:指的是vue实例化对象
渐进式的javascript框架
渐进式是什么意思?
- 1.如果你已经有一个现成的服务端应用,你可以将vue 作为该应用的一部分嵌入其中,带来更加丰富的交互体验;
- 2.如果你希望将更多业务逻辑放到前端来实现,那么VUE的核心库及其生态系统也可以满足你的各式需求(core+vuex+vue-route)。和其它前端框架一样,VUE允许你将一个网页分割成可复用的组件,每个组件都包含属于自己的HTML、CSS、JAVASCRIPT以用来渲染网页中相应的地方。
- 3.如果我们构建一个大型的应用,在这一点上,我们可能需要将东西分割成为各自的组件和文件,vue有一个命令行工具,使快速初始化一个真实的工程变得非常简单(vue init webpack my-project)。
我们可以使用VUE的单文件组件,它包含了各自的HTML、JAVASCRIPT以及带作用域的CSS或SCSS。以上这三个例子,是一步步递进的,也就是说对VUE的使用可大可小,它都会有相应的方式来整合到你的项目中。所以说它是一个渐进式的框架。VUE最独特的特性:响应式系统VUE是响应式的(reactive),也就是说当我们的数据变更时,VUE会帮你更新所有网页中用到它的地方。
Vue双向绑定
- vue实现数据双向绑定主要是:采用数据劫持结合发布者订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。
- vue的数据双向绑定 将MVVM作为数据绑定的入口,整合Observer,Compile和Watcher三者,通过Observer来监听自己的model的数据变化,通过Compile来解析编译模板指令(vue中是用来解析 {{}}),最终利用watcher搭起observer和Compile之间的通信桥梁,达到数据变化 —>视图更新;视图交互变化(input)—>数据model变更双向绑定效果。
Vue生命周期
什么是vue生命周期?
Vue 实例从创建到销毁的过程,就是生命周期。从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、销毁等一系列过程,称之为 Vue 的生命周期。
Vue生命周期的作用
它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。
Vue生命周期的过程
它可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后。
beforeCreate(创建前) 在数据观测和初始化事件还未开始
created(创建后) 完成数据观测,属性和方法的运算,初始化事件,el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互。
beforeUpdate(更新前) 在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。
updated(更新后) 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
beforeDestroy(销毁前) 在实例销毁之前调用。实例仍然完全可用。
destroyed(销毁后) 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。
.第一次页面加载会触发哪几个钩子?
会触发 下面这几个beforeCreate, created, beforeMount, mounted 。
DOM 渲染在 哪个周期中就已经完成?
DOM 渲染在 mounted 中就已经完成了。
Vue三种常用传值方式
父组件向子组件传值
- 使用props建立数据通道的渠道
- 在子组件中通过props传递过来的数据
子组件向父组件传值
- 子组件中需要一个点击事件触发一个自定义事件
- 在父组件中的子标签监听该自定义事件得到传递的值
非父子组件传值
- 1他们之间有一个共同的容器,假设A和B之间传值,我们可以用localstoage和SessionStorage把A的数据传给共同的容器,然后B从这个容器中再把A的数据取出来。
- 2.可以先定义一个bus的空对象,首先A通过‘emit发送数据到bus这个空对象中,然后B通过emit发送数据到bus这个空对象中,然后B通过on来接收这个空对象的数据。
- 3.vuex集中管理的方式传值也是和上面一样的办法,只是在数据较多且复杂的情况下才用,具体操作都是通过一个中间人来传递数据。
Vuex
Vuex是什么
Vuex是一个专门为Vue.js应用程序开发的状态管理模式, 它采用集中式存储管理所有组件的公共状态, 并以相应的规则保证状态以一种可预测的方式发生变化.
vuex的核心概念
- vuex五大核心属性:state,getter,mutation,action,module
- getter:可以认为是 store 的计算属性,它的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
- mutation:更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
- action:包含任意异步操作,通过提交 mutation 间接更变状态。
- module:将 store 分割成模块,每个模块都具有state、mutation、action、getter、甚至是嵌套子模块。
vuex的数据传递流程
当组件进行数据修改的时候我们需要调用dispatch来触发actions里面的方法。actions里面的每个方法中都会有一个commit方法,当方法执行的时候会通过commit来触发mutations里面的方法进行数据的修改。mutations里面的每个函数都会有一个state参数,这样就可以在mutations里面进行state的数据修改,当数据修改完毕后,会传导给页面。页面的数据也会发生改变。
为什么要用vuex
由于传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致代码无法维护。所以我们需要把组件的共享状态抽取出来,以一个全局单例模式管理。在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!另外,通过定义和隔离状态管理中的各种概念并强制遵守一定的规则,我们的代码将会变得更结构化且易维护。
mysql各字段的区别
char,varchar和text
- char是采用固定长度存储数据,也就是数据初始化为该类型的字段分配固定长度的存储空间,即使没有达到存储空间的长度,实际占用的存储空间也是定义时的长度。当存储的字符串没有达到char的最大长度时,字符串后面是不会以空格来填充的,而且char会过滤字符串末端的空格然后存储,而在比较字符串的时候又会自动空格填充到字符串的末端。虽然浪费存储空间,但是它固定长度,索引效率极高,不存在碎片。最多能存放的字符个数 255。
- varchar是存储可变长度的字符串,我们可以指定的字段长度的最大长度,当字符串没有达到最大长度的时候以字符串的实际长度来存储的,不占用多余的存储空间。varchar不定长,索引速度没有char快。理论上可以添加全部索引,但是数据长度太大时索引也会截取数据前面的一部分。但是如果字段的长度越大,在字段不完全填充的情况下,varchar的性能优势就越明显。最多能存放 65532 个字符。
int、tinyint、float与decimal
- TINYINT一个很小的整数。有符号的范围是-128到127,无符号的范围是0到255。一个字符
- SMALLINT一个小整数。有符号的范围是-32768到32767,无符号的范围是0到65535。两个字符
- MEDIUMINT一个中等大小整数。有符号的范围是-8388608到8388607,无符号的范围是0到16777215。三个字符
- INT一个正常大小整数。有符号的范围是-2147483648到2147483647,无符号的范围是0到4294967295。四个字符
- BIGINT一个大整数。有符号的范围是-9223372036854775808到9223372036854775807,无符号的范围是0到18446744073709551615。八个字符。注意,所有算术运算用有符号的BIGINT或DOUBLE值完成,因此你不应该使用大于9223372036854775807(63位)的有符号大整数,除了位函数!
- FLOAT一个小(单精密)浮点数字。不能无符号。允许的值是-3.402823466E+38-1.175494351E-38,0 和1.175494351E-38到3.402823466E+38。没有参数的FLOAT或有<24 的一个参数表示一个单精密浮点数字。
- DOUBLE一个正常大小(双精密)浮点数字。不能无符号。允许的值是-1.7976931348623157E+308到-2.2250738585072014E-308、 0和2.2250738585072014E-308到1.7976931348623157E+308。
- decimal表示数值的精度,即实际保存到数据库的有效数字的总个数; 第二个参数代表小数点后的位数
DATE,DATETIME,TIME,TIMESTAMP,YEAR;
- DATE 为年月日的日期格式,标准格式为YYYY-MM-DD,但是mysql中还支持一些不严谨的格式:比如YYYY/MM/DD等其他的符号来分割,在插入数据的数据的也可以使用YY-MM-DD 年份的转换,可以使用CURRENT_DATE() 函数获取当前的DATE值,占三个字节
- DATETIME 为年月日时分秒的混合时间格式,DATE和TIME类型的结合体,占八个字节
- YEAR 为年份的时间的格式,占一个字节
- TIME 为时分秒的时间格式时间范围为0~23,但是为了表示某些特殊的时间,mysql将小时的范围扩大了,并且支持负值。对于TIME类型复制,标准的格式为HH:MM:SS,但不一定要这个格式,在mysql中,系统可以自动识别HHMMSS转化为标准格式.我们可以通过CURRENT_TIME()获取当前的TIME值,三个字节
- TIMESTAMP 为年月份时分秒的混合时间格式,以时间戳的格式存储。取值范围比DATETIME小,因此输入时一定要注意输入值的范围,超过范围会当作零值处理。占四个字节
PSR0~4
psr0(官方已废弃)
自动加载标准
- 一个完全合格的namespace和class必须符合这样的结构:“< Vendor Name>(< Namespace>)*< Class Name>”
- 每个namespace必须有一个顶层的namespace("Vendor Name"提供者名字)
- 每个namespace可以有多个子namespace
- 当从文件系统中加载时,每个namespace的分隔符(/)要转换成DIRECTORY_SEPARATOR(操作系统路径分隔符)
- 在类名中,每个下划线要转换成DIRECTORY_SEPARATOR(操作系统路径分隔符)。在namespace中,下划线是没有(特殊)意义的。
- 当从文件系统中载入时,合格的namespace和class一定是以 .php 结尾的verdor name,namespaces,class名可以由大小写字母组合而成(大小写敏感的)
psr1
基本代码规范
PHP源文件必须只使用 <?php 和 <?= 这两种标签。(php标记有多种方式)
源文件中php代码的编码格式必须是不带字节顺序标记(BOM)的UTF-8。(注:PHP在设计时就没有考虑BOM的问题,也就是说他不会忽略UTF-8编码的文件开头BOM的那三个字节导致出现奇怪的错误。)
一个源文件建议只用来做声明(类(class),函数(function),常量(constant)等)或者只用来做一些引起从属效应的操作(例如:输出信息,包含文件,修改.ini配置等),但不能同时使用两者。
注:“从属效应”(side effects)一词的意思是,仅仅通过包含文件,不直接声明类、函数和常量等,而执行的逻辑操作。 “从属效应”包含却不仅限于:生成输出、直接的 require 或 include、连接外部服务、修改 ini 配置、抛出错误或异常、修改全局或静态变量、读或写文件等。 这个很多人都不遵守,但是基本上所有框架里都不会把修改.ini配置和声明类或函数放到一起,比如框架index.php入口文件只定义宏常量和修改.ini等命名空间(namespace)和类(class) 必须遵守PSR0或psr4标准。
类名(class name) 必须使用骆驼式(StudlyCaps)写法(注:StudlyCaps即首字母大写驼峰式)。
类(class)中的常量必须只由大写字母和下划线组成。
方法名(method name) 必须使用驼峰式(cameCase)写法。
psr2
代码风格
- 代码必须遵循PSR-1中的编码规范
- 代码必须使用四个空格符而不是tab键进行缩进。
- 每行的字符数应该软性保持在80个内,理论上不可多于120个,但一定不能硬性限制
- 每个namespace命名空间声明语句和use语句块后面,必须插入一个空白行
- 类的开始花括号必须在类声明后自成一行,结束花名号也必须在类主体后自成一行
- 函数的开始花括号必须在函数声明后自成一行,结束花名号也必须在函数主体后自成一行
- 类的属性和方法必须添加访问修饰符(private protected以及public),abstract以及final必须声明在访问修饰符之前,而static必须声明在访问修饰符之后。
- 控制结构的关键字后必须要有一个空格符,而调用方法或函数时则一定不能有。
- 控制结构的开始花括号必须写在声明的同一行,而结束花括号必须写在主体后自成一行。
- 控制结构的开始左括号后和结束右括号前,都一定不能有空格符。
注意
对于php文件:
- 所有的php文件都必须以Unix LF(换行)作为结束符
- 所有的php文件都必须以一个单独的空行结尾
- 纯PHP代码源文件的关闭标签?>必须省略。
关键字和 True/False/Null
- php的关键字,必须小写
- php产量 true ,false,null也必须小写
命名空间
- 命名空间(namespace)的声明后面必须有一行空行。
- 所有的导入(use)声明必须放在命名空间(namespace)声明的下面。
- 一句声明中,必须只有一个导入(use)关键字。
- 在导入(use)声明代码块后面必须有一行空行。
控制结构
if ,else ,elseif ,while ,do while ,switch case ,for, foreach,try catch等。这一类的写法规范也是经常容易出现问题的,也要规范一下。在关键字和后面的判断条件中间应该加空格,在判断条件和左大括号之间也要加空格。
psr3
日志接口规范
- 它的主要目的,是为了让类库以简单通用的方式接收一个Psr\Log\LoggerInterface对象,来记录日志信息。框架以及CMS内容管理系统如有需要,可以扩展接口以用于它们自己的目的,但须遵循本规范,才能在使用第三方的类库文件时,保证日志接口仍能正常对接。
- LoggerInterface 接口对外定义了八个方法,分别用来记录RFC 5424中定义的八个级别:debug、info、notice、warning、error、critical、alert,emergency。
- 第九个方法-log,其第一个参数为日志的等级,可使用一个预定义好的等级常量作为参数来调用此方法,必须与直接调用以上八个方法具有相同的效果。如果传入的等级常量参数没有预先定义,就必须抛出Psr\Log\InvalidArgumentException类型的异常,在不确定的情况下,使用者不该使用未支持的等级常量来调用此方法。如果有用过monolog就应该对这里有较深的理解。
psr4
升级版的PSR-0自动加载规范
PSR4是关于由文件路径自动载入对应的类的相关规范,本规范是可互操作的。可以作为任一自动(包括PSR-0)载入规范的补充,此外,PSR4还包括自动载入的类对应的文件存放路径规范。此处的“类”泛指所有的class类、接口、traits可复用代码块以及其他类似结构。
一个完整的类名需要具有以下结构<命名空间>(<子命名空间>)*<类名>
- 完整的类名必须要有一个顶级命名空间,被称为“Vendor namespace”
- 完整的类名可以有一个或多个子命名空间
- 完整的类名必须有一个最终的类名
- 完整的类名中任意一部分中的下划线都是没有特殊意义的
- 完整的类名可以由任意大小写字母组成
- 所有类名都必须是大小写敏感的
当根据完整的类名载入相应的文件
- 完整的类名中,去掉最前面的命名空间分隔符,前面连续的一个或多个命名空间和子命名空间,作为“命名空间前缀”,其必须至少对应一个基础目录。
- 紧接命名空间前缀后的子命名空间必须与相对应的“基础目录”的子目录相匹配,其中的命名空间分隔符作为目录分割符
- 末尾的类名必须与对应的.php为后缀的文件同名
- 自动加载器(autoloader)的实现一定不能抛出异常,一定不能触发任一级别的错误信息以及不应该有返回值。
PSR-4和PSR-0最大的区别是对下划线(underscore)的定义不同。PSR-4中,在类名中使用下划线没有任何特殊含义。而PSR-0则规定类名中的下划线_会被转化成目录分隔符。
网友评论