写个快速排序热热身,分析一下复杂度,如果不使用额外的空间,应该怎么写?
def quick_sort(lists, left, right):
# 快速排序
if left >= right:
return lists
key = lists[left]
low = left
high = right
while left < right:
while left < right and lists[right] >= key:
right -= 1
lists[left] = lists[right]
while left < right and lists[left] <= key:
left += 1
lists[right] = lists[left]
lists[right] = key
quick_sort(lists, low, left - 1)
quick_sort(lists, left + 1, high)
return lists # 递归
参考算法图解,使用递归,分而治之,重要点是找到 基线条件 和
递归条件 ,然后编写快速排序。
八大排序算法的 Python 实现
python快速排序的两种方法
说一下Flask中g是怎么实现的,原理是什么?
解释一
这个问题我也遇到了,楼上的各位大牛都说得很抽象,但应该是正确理解这个问题的方向。我谈谈自己的理解吧。1. app context
和 request contextrequest context
很好理解,看名字就知道是 请求上下文。而 app context
却有点误导性,它的字面意思是 应用上下文,但它不是一直存在的,它只是request context
中的一个对 app 的代理(人),所谓local proxy
。它的作用主要是帮助 request 获取当前的应用,它是伴 request
而生,随request
而灭的。为什么需要这个代理?因为 flask 支持同时运行多个 app,所以需要为每个 request
绑定到具体的app context
。举例说request A
要改变 app A
的属性,就要把request A
绑定到app A
的 context
下。(这里我是猜的,因为我的水平还不涉及到多应用……)
-
g
和session
从第一点可以明白app context
的生命周期其实也只有一个 request 那么长。既然这样,那么像g这样的属于app context
的变量当然也是只有一个request
那么长的生命周期了。这就是为什么你的代码在另一个request
中读取g.count
会报错的原因。要达到你想要的效果,你可以使用其session
。稍微读一下源码你就会发现session
也是一个 request context 的变量,但它把数据保存到了 cookie 中并发送到了客户端,客户端再次请求的时候又带上了cookie。
解释二
Flask本身代码很简单,所以,了解Thread local context
是最大的难点把。 Local对象的作用就是,它是一个全局对象,你可以往里面保存东西,a线程保存到local对象的,只有a线程能取到,b线程的只有b线程能取到,如果,a,b保存了名字相同的东西,比如x,a取到的值是自己保存的,不会和b保存的混淆,修改操作也一样。 request,session,g都是用相同的原理实现的,都是保存在local对象里的线程(包括greenlet协程)安全的变量。 flask自己实现了local对象而不是使用标准库的threading.Local
对象。 仔细读下werkzueg
的local
代码和docstring
解释三
《Flask 0.7中文手册》P37页提到,g保存一个request的全局变量(译者:g保存的是当前请求的全局变量,不同的请求会有不同的全局变量,通过不同的thread id区别)
Flask 的 Context 机制
官方文档使用Dash查找 g
说一下浏览器从输入url到页面渲染的过程,越详细越好;
TCP/UDP协议 区别 ?
TCP (Transmission Control Protocol 传输控制协议) 和 UDP(User Datagram Protocol用户数据报协议) 协议属于传输层协议(端口与端口之间)
面向连接的TCP
“面向连接”就是在正式通信前必须要与对方建立起连接。比如你给别人打电话,必须等线路接通了、对方拿起话筒才能相互通话。
个TCP连接必须要经过三次“对话”才能建立起来,其中的过程非常复杂,我们这里只做简单、形象的介绍:
主机A向主机B发出连接请求数据包:“我想给你发数据,可以吗?”,这是第一次对话;
主机B主机A发送同意连接和要求同步(同步就是两台主机一个在发送,一个在接收,协调工作)的数据包:“可以,你什么时候发?”,这是第二次对话;
主机A再发出一个数据包确认主机B的要求同步:“我现在就发,你接着吧!”,这是第三次对话。三次“对话”的目的是使数据包的发送和接收同步,经过三次“对话”之后,A才向B正式发送数据。
面向非连接的UDP协议
“面向非连接”就是在正式通信前不必与对方先建立连接,不管对方状态就直接发送。与手机短信非常相似:你在发短信的时候,只需要输入对方手机号就OK了。
TCP与UDP基本区别
1.基于连接与无连接
2.TCP要求系统资源较多,UDP较少;
3.UDP程序结构较简单
4.流模式(TCP)与数据报模式(UDP);
5.TCP保证数据正确性,UDP可能丢包
6.TCP保证数据顺序,UDP不保证
UDP应用场景:
1.面向数据报方式
2.网络数据大多为短消息
3.拥有大量Client
4.对数据安全性无特殊要求
5.网络负担非常重,但对响应速度要求高
具体编程时的区别:
- socket()的参数不同
- UDP Server不需要调用listen和accept
- UDP收发数据用sendto/recvfrom函数
- TCP:地址信息在connect/accept时确定
- UDP:在sendto/recvfrom函数中每次均 需指定地址信息
- UDP:shutdown函数无效
参考
了解web安全吗?说一下XSS原理
如果把浏览器看作WEB2.0后时代的操作系统,那么客户端脚本就相当于传统的应用程序,而XSS的攻击方式其实就相当于在被攻击者的系统上执行了一个木马程序。但这种“木马”有个很大的缺点,就是无法像传统木马那样在操作系统中安家,以后还能自动执行。
XSS又叫CSS (Cross Site Script) ,跨站脚本攻击。它指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意攻击用户的特殊目的。
为什么会出现XSS呢,这个没什么好说的,肯定是过滤不严,或者就是程序猿认为XSS并没有什么实际的用途,从而忽略了XSS攻击的产生。
图解HTTP的解释:
跨站脚本攻击(Cross-Site Scripting,XSS)是指通过存在安全漏洞 的 Web 网站注册用户的浏览器内运行非法的 HTML 标签或 JavaScript 进行的一种攻击。动态创建的 HTML 部分有可能隐藏着安全漏洞。就 这样,攻击者编写脚本设下陷阱,用户在自己的浏览器上运行时,一不 小心就会受到被动攻击。
跨站脚本攻击有可能造成以下影响。
● 利用虚假输入表单骗取用户个人信息。
● 利 用脚本窃取用户的 Cookie 值,被害者在不知情的情况下,帮助攻击者发送恶意请求。
● 显示伪造的文章或图片。
其他常见的攻击方式:
针对WEB的攻击技术:
- HTTP 不具备必要的安全功能
- 在客户端即可篡改请求
- 针对 Web 应用的攻击模式 主动 被动
因输出值转义不完全引发的安全漏洞:
- 跨站脚本攻击
- SQL 注入攻击
- OS 命令注入攻击
- HTTP 或 邮件 首部注入攻击
- 目录遍历攻击
- 远程文件包含漏洞
因设置或设计上的缺陷引发的安全漏洞:
- 强制浏览
- 不正确的错误消息处理
- 开放重定向
因会话管理疏忽引发的安全漏洞:
- 会话劫持
- 会话固定攻击
- 跨站点请求伪造
说一下 CSRF 的理解;
跨站点请求伪造(Cross-Site Request Forgeries,CSRF)攻击是指攻 击者通过设置好的陷阱,强制对已完成认证的用户进行非预期的个人信 息或设定信息等某些状态更新,属于被动攻击。
跨站点请求伪造有可能会造成以下等影响:
● 利用已通过认证的用户权限更新设定信息等
● 利用已通过认证的用户权限购买商品
● 利用已通过认证的用户权限在留言板上发表言论
百科
session和cookie的区别
由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识具体的用户,这个机制就是Session.典型的场景比如购物车,当你点击下单按钮时,由于HTTP协议无状态,所以并不知道是哪个用户操作的,所以服务端要为特定的用户创建了特定的Session,用用于标识这个用户,并且跟踪用户,这样才知道购物车里面有几本书。这个Session是保存在服务端的,有一个唯一标识。在服务端保存Session的方法很多,内存、数据库、文件都有。集群的时候也要考虑Session的转移,在大型的网站,一般会有专门的Session服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存的,使用一些缓存服务比如Memcached之类的来放 Session。
思考一下服务端如何识别特定的客户?这个时候Cookie就登场了。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。实际上大多数的应用都是用 Cookie 来实现Session跟踪的,第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,需要在 Cookie 里面记录一个Session ID,以后每次请求把这个会话ID发送到服务器,我就知道你是谁了。有人问,如果客户端的浏览器禁用了 Cookie 怎么办?一般这种情况下,会使用一种叫做URL重写的技术来进行会话跟踪,即每次HTTP交互,URL后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户。
Cookie其实还可以用在一些方便用户的场景下,设想你某次登陆过一个网站,下次登录的时候不想再次输入账号了,怎么办?这个信息可以写到Cookie里面,访问网站的时候,网站页面的脚本可以读取这个信息,就自动帮你把用户名给填了,能够方便一下用户。这也是Cookie名称的由来,给用户的一点甜头。
所以,总结一下:
Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;
Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。
数据库的索引,说一下非主键索引是怎么实现的?
数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B+树。
在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是索引。
参考文章 里面详细些
说一下你最近看的三本书,介绍一下
尽量要说计算机相关的,一定要熟悉,否则打脸
tcp粘包是什么,怎么办?
1. 什么是粘包现象
TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。
2. 为什么出现粘包现象
(1)发送方原因
我们知道,TCP默认会使用Nagle算法。而Nagle算法主要做两件事:1)只有上一个分组得到确认,才会发送下一个分组;2)收集多个小分组,在一个确认到来时一起发送。
所以,正是Nagle算法造成了发送方有可能造成粘包现象。
(2)接收方原因
TCP接收到分组时,并不会立刻送至应用层处理,或者说,应用层并不一定会立即处理;实际上,TCP将收到的分组保存至接收缓存里,然后应用程序主动从缓存里读收到的分组。这样一来,如果TCP接收分组的速度大于应用程序读分组的速度,多个包就会被存至缓存,应用程序读时,就会读到多个首尾相接粘到一起的包。
3. 什么时候需要处理粘包现象
(1)如果发送方发送的多个分组本来就是同一个数据的不同部分,比如一个很大的文件被分成多个分组发送,这时,当然不需要处理粘包的现象;
(2)但如果多个分组本毫不相干,甚至是并列的关系,我们就一定要处理粘包问题了。比如,我当时要接收的每个分组都是一个有固定格式的商品信息,如果不处理粘包问题,每个读进来的分组我只会处理最前边的那个商品,后边的就会被丢弃。这显然不是我要的结果。
4. 如何处理粘包现象
(1)发送方
对于发送方造成的粘包现象,我们可以通过关闭Nagle算法来解决,使用TCP_NODELAY选项来关闭Nagle算法。
(2)接收方
遗憾的是TCP并没有处理接收方粘包现象的机制,我们只能在应用层进行处理。
(3)应用层处理
应用层的处理简单易行!并且不仅可以解决接收方造成的粘包问题,还能解决发送方造成的粘包问题。
解决方法就是循环处理:应用程序在处理从缓存读来的分组时,读完一条数据时,就应该循环读下一条数据,直到所有的数据都被处理;但是如何判断每条数据的长度呢?
两种途径:
1)格式化数据:每条数据有固定的格式(开始符、结束符),这种方法简单易行,但选择开始符和结束符的时候一定要注意每条数据的内部一定不能出现开始符或结束符;
2)发送长度:发送每条数据的时候,将数据的长度一并发送,比如可以选择每条数据的前4位是数据的长度,应用层处理时可以根据长度来判断每条数据的开始和结束。
当时在做购物车的时候,我最开始的做法是设置开始符(0x7e)和结束符(0xe7),但在测试大量数据的时候,发现了数据异常。正如我所猜测,在调试过程中发现某些数据内部包含了它们。因为要处理的数据是量非常庞大,为做到万无一失,最后我采用了发送长度的方式。再也没有因为粘包而出过问题。
正常情况下UDP不会粘包
UDP有明确的结束标志,不会有粘包的,UDP本身有对数据完整性的校验,不完整的包会被丢弃,所以也不会不完整。
更多详解