网络编程和并发

前篇文章中主要总结了Alex的相关Python的基础知识题目。

这篇文章主要介绍相关网络编程与并发。

简述 OSI 七层协议。

应用层(Application)、表示层(presentation)、会话层(session)、传输层(Transport)、网络层(Network)、数据链路层(Data Link)、物理层(Physical)。

每一层实现各自的功能和协议,并完成与相邻接口通信,OSI的服务定义详细说明了各层所提供的服务。某一层的服务就是该层及其下各层的一种能力,它通过接口提供给更高一层。各层所提供的服务与这些服务是怎么实现的无关。

应用层

OSI 参考模型中最靠近用户的一层,是为计算用户提供应用接口,也为用户直接提供网络服务。常见的应用层网络服务协议有:HTTP,HTTPS,FTP,POP3,SMTP等

表示层

表示提供各种用于应用层数据编码和转换功能,确保一个系统的应用层发送的数据能被另一个系统的应用层识别。如果必要该层可提供一种标准表示形式,用于将计算机内部的多种数据格式转换成通信中采用的标准表示形式。数据压缩和加密也是表示层可提供的转换功能之一。

会话层

会话层负载建立、管理和终止表示层实体之间的通信会话。该层的通信由不同设备中的应用程序之间的服务请求和响应组成。

传输层

传输层建立了主机端到端的链接,传输层的作用是为上层协议提供端到端的可靠和透明的数据传输服务,包括处理差错控制和流量控制等问题。该层向高层屏蔽了下层数据通信的细节,是高层用户看到的只是在两个传输实体建的一个主机到主机的、可由用户控制和设定、可靠的数据通路。通常说的TCP UDP就是在这层。端口号即是这里的“端”。

网络层

本层通过IP寻址来建立两点之间的连接,为源端的运输层来的分组,选择合适的路由和交换节点,正确无误地按照地址传送给目的端的运输层。就是通常说的ip层。这一层就是我们经常说的IP协议层。IP协议是Internet的基础。

数据链路层

将比特组合成字节,再将字节组成帧,使用链路层地址(以太网mac地址)来访问介质,并进行差错检测。

数据链路层又分为2个子层:逻辑链路控制子层(LLC)和媒体访问控制子层(MAC)。

物理层

实际最终信号传输是通过物理层实现的。通过物理介质传输比特流。规定电平、速度和电缆针脚。常用设备有(各种物理设备)集线器、中继器、调制解调器、网线、双绞线、同轴电缆。这些都是物理层的传输介质。

什么是C/S和B/S架构?

C/S架构是一种比较早的软件架构,主要应用于局域网内。在这之前经历了集中计算模式,随着计算机网络的进步与发展,尤其是可视化工具的应用,出现过两层C/S和三层C/S架构,不过一直很流行也比较经典的是我们所要研究的两层C/S架构。

C/S架构的优点

a. 客户端和服务器直接相连。点对点的连接方式更安全,可以直接操作本地文本,比较方便。

b. 客户端可以处理一些逻辑事务。可以进行数据处理和数据存储,提供一定的帮助。

c. 客户端直接操作界面。

3. C/S架构的缺点

a. C/S架构适用于局域网,对网速的要求比较高。

b.客户端界面缺乏通用性,且当业务更改时就需要更改界面,重新编写。

c. 随着用户数量的增多,会出现通信拥堵、服务器响应速度慢等情况。

d.系统的维护也比较麻烦。

C/S架构的应用

C/S架构的软件是在是数不胜数,从办公的OFFICE,WPS,WINRAR到杀毒软件如金山,瑞金再到我们的娱乐软件,如播放器,QQ,微信等,还有游戏等等,无处不见C/S架构。

B/S架构及其背景

随着Internet和WWW的流行,以往的主机/终端和C/S都无法满足当前的全球网络开放、互连、信息随处可见和信息共享的新要求,于是就出现了B/S型模式,即浏览器/服务器结构。它是C/S架构的一种改进,可以说属于三层C/S架构。主要是利用了不断成熟的WWW浏览器技术,用通用浏览器就实现了原来需要复杂专用软件才能实现的强大功能,并节约了开发成本,是一种全新的软件系统构造技术。

B/S架构的优点

a. 浏览器和数据库服务器采用多对多的方式连接。因此适合在广域网里实现巨大的互联网,甚至是全球网,有着很强大的信息共享性。

b. 浏览器只处理一些简单的逻辑事务,负担小。

c.数据都集中存放在数据库服务器,所以不存在数据不一致现象。

d.随着服务器负载的增加,可以平滑地增加服务器的个数并建立集群服务器系统,然后在各个服务器之间做负载均衡。

e.B/S建立在广域网上,所以需要的网速要求不高。

f.不需要安装客户端,只要能连上网,就能随时随地的浏览页面。

g.能有效地保护数据平台和管理访问权限,确保服务器数据库的数据安全。

B/S架构的缺点

a. 服务器承担着重要的责任,数据负荷较重。一旦发生服务器“崩溃”等问题,后果不堪设想。

b.页面需要不断地动态刷新,当用户增多时,网速会变慢。

B/S架构的应用

比如WEBQQ,从WEBQQ名称中的WEB就不难看出它属于B/S架构,是一种浏览器服务器结构。事实上也是如此,因为WEBQQ根本不需要安装客户端,只需要有浏览器就可以进行聊天交互了。

简述 三次握手、四次挥手的流程。

在TCP/IP协议中,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连接是全双工的,因此每个方向都必须单独进行关闭。这个原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送(报文段4)。

服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。

服务器B关闭与客户端A的连接,发送一个FIN给客户端A(报文段6)。

客户端A发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。

网络Socket编程与Socket API的过程。

可以看到,只有当server端listen之后,client端调用connect才能成功,否则就会返回RST响应拒绝连接。

只有当accept后,client和server才能调用recv和send等io操作。

socket API调用错误不会导致client出现SYN_SENT状态,那么只能是网络设备丢包(路由器、防火墙)才会导致SYNC_SENT状态。

TCP断连过程说明。

close只是减少socket文件的引用计数,当计数减为0后,操作系统执行tcp的断连操作。

client端close后server端不close,会导致client端连接状态为FIN_WAIT_2,server端连接状态为CLOSE_WAIT。

正常编程肯定不会这样处理,一般都是在异常处理跳转(C++/JAVA等)导致没有close,或者整个系统异常导致没有close(例 如JVM内存出现out of memory错误)。

shutdown的处理逻辑比较复杂,非特殊情况不要乱用,很容易出问题。

进程退出后操作系统会自动回收socket,发起tcp关闭流程操作。

其中tcp三次握手与四次分手的各种状态的详解。

CLOSED: 这个没什么好说的了,表示初始状态即关闭状态。

LISTEN: 这个也是非常容易理解的一个状态,表示服务器端的某个SOCKET处于监听状态,可以接受连接了。

SYN_RCVD: 这个状态表示接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本 上用netstat你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态 时,当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。

SYN_SENT: 这个状态与SYN_RCVD遥想呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,因此也随即它会进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。

ESTABLISHED:这个容易理解了,表示连接已经建立了。

FIN_WAIT_1: 这个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别 是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即 进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马 上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。

FIN_WAIT_2:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。

TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。

CLOSING: 这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的 ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什 么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报 文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接。

CLOSE_WAIT: 这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以 close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。

LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。

推荐博客:

什么是arp协议?

ARP,我们经常听到的这些术语,包括"网络扫描"、"内网渗透"、"中间人拦截"、"局域网流控"、"流量欺骗",基本都跟ARP脱不了干系。大量的安全工具,例如大名鼎鼎的Cain、功能完备的Ettercap、操作傻瓜式的P2P终结者,底层都要基于ARP实现。

ARP(Address Resolution Protocol)即地址解析协议, 用于实现从 IP 地址到 MAC 地址的映射,即询问目标IP对应的MAC地址。

在网络通信中,主机和主机通信的数据包需要依据OSI模型从上到下进行数据封装,当数据封装完整后,再向外发出。所以在局域网的通信中,不仅需要源目IP地址的封装,也需要源目MAC的封装。

一般情况下,上层应用程序更多关心IP地址而不关心MAC地址,所以需要通过ARP协议来获知目的主机的MAC地址,完成数据封装。

ARP协议通过"一问一答"实现交互,但是"问"和"答"都有讲究,"问"是通过广播形式实现,"答"是通过单播形式。

TCP和UDP的区别?

TCP面向连接(如打电话要先拨号建立连接)。UDP是无连接的,即发送数据之前不需要建立连接。

TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达。UDP尽最大努力交付,即不保证可靠交付。

TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流。UDP是面向报文的。

UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)。

每一条TCP连接只能是点到点的。UDP支持一对一,一对多,多对一和多对多的交互通信。

TCP首部开销20字节;UDP的首部开销小,只有8个字节。

TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道。

网络中的进程如何通信。

消息传递(管道、FIFO、消息队列)。

同步(互斥量、条件变量、读写锁、文件和写记录锁、信号量)。

共享内存(匿名的和具名的)。

远程过程调用(Solaris门和Sun RPC)。

什么是局域网和广域网?

局域网LAN(Local Area Network):一般指覆盖范围在10公里以内,一座楼房或一个单位内部的网络。由于传输距离直接影响传输速度,因此,局域网内的通信,由于传输于距离短,传输的速率一般都比较高。目前,局域网的传输速率一般可达到10MB/S和100MB/S,高速局域网传输速率可达到1000MB/S。

广域网WAN(Wide Area Network):是指远距离的、大范围的计算机网络。跨地区、跨城市、跨国家的网络都是广域网。由于广域的覆盖范围广,联网的计算机多,因此广域网上的信息量非常大,共享的信息资源很丰富。INTERNET是全球最大的广域网,它覆盖的范围遍布全世界。

城域网MAN(Metropolitan Area Network):其覆盖范围在局域网和广域网之间。一般指覆盖范围为一个城市的网络。

为何基于tcp协议的通信比基于udp协议的通信更可靠?

tcp: 可靠,对方给了确认收到信息,才发下一个,如果没收到确认信息就重发。

udp: 不可靠,一直发数据,不需要对方回应。

TCP---传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。

UDP---用户数据报协议,是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。

基于tcp的数据传输,tcp在数据传输时,发送端先把数据发送到自己的缓存中,然后协议控制将缓存中的数据发往对端,对端返回一个ack=1,发送端则清理缓存中的数据,对端返回ack=0,则重新发送数据,所以tcp是可靠的。而udp发送数据,对端是不会返回确认信息的,因此不可靠。

什么是socket?简述基于tcp协议的套接字通信流程。

连接实际上是操作系统内核的一种数据结构,称为TCP控制块(TCB),对于linux而言是tcp_sock结构。不光连接,连数据包也是由一个数据结构来控制,linux里面称为sk_buff结构。

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部。

服务端:创建socket对象,绑定ip端口bind(), 设置最大链接数listen(), accept()与客户端的connect()创建双向管道, send(), recv(),close()。

客户端:创建socket对象,connect()与服务端accept()创建双向管道 , send(), recv(),close()。

通过三次握手后建立连接,开始收发消息。收发消息完了之后,通过四次挥手断开连接。

什么是粘包? socket 中造成粘包的原因是什么? 哪些情况会发生粘包现象?

粘包:多个数据包被连续存储于连续的缓存中,在对数据包进行读取时由于无法确定发生方的发送边界,而采用某一估测值大小来进行数据读出,若双方的size不一致时就会使指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方造成。

发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据。

接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据。

当时短连接的情况下,不用考虑粘包的情况。

如果发送数据无结构,如文件传输,这样发送方只管发送,接收方只管接收存储就ok,也不用考虑粘包。

缓冲区过大造成了粘包,所以在发送/接收消息时先将消息的长度作为消息的一部分发出去,这样接收方就可以根据接收到的消息长度来动态定义缓冲区的大小。(这种方法就是所谓的自定义协议,这种方法是最常用的)。

对发送的数据进行处理,每条消息的首尾加上特殊字符,然后再把要发送的所有消息放入一个字符串中,最后将这个字符串发送出去,接收方接收到这个字符串之后,再通过特殊标记操作字符串,把每条消息截出来。(这种方法只适合数据量较小的情况) 。

为什么基于TCP的通信程序需要封包、拆包?

TCP是流协议,所谓流,就是没有界限的一串数据。但是程序中却有多种不同的数据包,那就很可能会出现如上所说的粘包问题,所以就需要在发送端封包,在接收端拆包。

那么如何封包、拆包?

封包就是给一段数据加上包头或者包尾。比如说我们上面为解决粘包所使用的两种方法,其实就是封包与拆包的具体实现。

IO多路复用的作用?

服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种。

同步阻塞IO(Blocking IO):即传统的IO模型。

同步非阻塞IO(Non-blocking IO):默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK。注意这里所说的NIO并非Java的NIO(New IO)库。

IO多路复用(IO Multiplexing):即经典的Reactor设计模式,有时也称为异步阻塞IO,Java中的Selector和Linux中的epoll都是这种模型。

异步IO(Asynchronous IO):即经典的Proactor设计模式,也称为异步非阻塞IO。

同步和异步的概念描述的是用户线程与内核的交互方式:同步是指用户线程发起IO请求后需要等待或者轮询内核IO操作完成后才能继续执行;而异步是指用户线程发起IO请求后仍继续执行,当内核IO操作完成后会通知用户线程,或者调用用户线程注册的回调函数。

阻塞和非阻塞的概念描述的是用户线程调用内核IO操作的方式:阻塞是指IO操作需要彻底完成后才返回到用户空间;而非阻塞是指IO操作被调用后立即返回给用户一个状态值,无需等到IO操作彻底完成。

I/O多路复用指:通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。

SocketServer模块

ThreadingTCPServer

SocketServer的ThreadingTCPServer之所以可以同时处理请求得益于 select 和 Threading 两个东西,其实本质上就是在服务器端为每一个客户端创建一个线程,当前线程用来处理对应客户端的请求。

ForkingTCPServer

SocketServer的ThreadingTCPServer之所以可以同时处理请求得益于 select 和 os.fork 两个东西,其实本质上就是在服务器端为每一个客户端创建一个进程,当前新创建的进程用来处理对应客户端的请求。

Twisted是一个事件驱动的网络框架,其中包含了诸多功能,例如:网络协议、线程、数据库管理、网络操作、电子邮件等。

Twisted本质上使用了事件驱动的方法和IO多路复用的机制来进行Socket的处理。

什么是防火墙以及作用?

防火墙作为一个边界防御工具,其监控流量——要么允许它、要么屏蔽它。 多年来,防火墙的功能不断增强,现在大多数防火墙不仅可以阻止已知的一些威胁、执行高级访问控制列表策略,还可以深入检查流量中的每个数据包,并测试包以确定它们是否安全。大多数防火墙都部署为用于处理流量的网络硬件,和允许终端用户配置和管理系统的软件。越来越多的软件版防火墙部署到高度虚拟化的环境中,以在被隔离的网络或 IaaS 公有云中执行策略。

select、poll、epoll 模型的区别?

只有IOCP是asynchronous I/O,其他机制或多或少都会有一点阻塞。

select低效是因为每次它都需要轮询。但低效也是相对的,视情况而定,也可通过良好的设计改善。

epoll、 kqueue、select是Reacor模式,IOCP是Proactor模式。

java nio包是select模型。

Linux并发网络编程模型

Apache 模型,简称 PPC (Process Per Connection):为每个连接分配一个进程。主机分配给每个连接的时间和空间上代价较大,并且随着连接的增多,大量进程间切换开销也增长了,很难应对大量的客户并发连接。

TPC 模型( Thread Per Connection ):每个连接一个线程,和PCC类似。

select 模型,I/O多路复用技术。

每个连接对应一个描述。select模型受限于 FD_SETSIZE即进程最大打开的描述符数。linux2.6.35为1024,实际上linux每个进程所能打开描数字的个数仅受限于内存大小,然而在设计select的系统调用时,却是参考FD_SETSIZE的值。可通过重新编译内核更改此值,但不能根治此问题,对于百万级的用户连接请求,即便增加相应 进程数, 仍显得杯水车薪。

select每次都会扫描一个文件描述符的集合,这个集合的大小是作为select第一个参数传入的值。但是每个进程所能打开文件描述符若是增加了 ,扫描的效率也将减小。

内核到用户空间,采用内存复制传递文件描述上发生的信息。

poll 模型:I/O多路复用技术。

poll模型将不会受限于FD_SETSIZE,因为内核所扫描的文件描述符集合的大小是由用户指定的,即poll的第二个参数。但仍有扫描效率和内存拷贝问题。

pselect模型:I/O多路复用技术。同select。

epoll模型:

无文件描述字大小限制仅与内存大小相关。

epoll返回时已经明确的知道哪个socket fd发生了什么事件,不用像select那样再一个个比对。

内核到用户空间采用共享内存方式,传递消息。

FAQ

单个epoll并不能解决所有问题,特别是你的每个操作都比较费时的时候,因为epoll是串行处理的。 所以你有还是必要建立线程池来发挥更大的效能。

如果fd被注册到两个epoll中时,如果有时间发生则两个epoll都会触发事件。

如果注册到epoll中的fd被关闭,则其会自动被清除出epoll监听列表。

如果多个事件同时触发epoll,则多个事件会被联合在一起返回。

epoll_wait会一直监听epollhup事件发生,所以其不需要添加到events中。

为了避免大数据量io时,et模式下只处理一个fd,其他fd被饿死的情况发生。linux建议可以在fd联系到的结构中增加ready位,然后epoll_wait触发事件之后仅将其置位为ready模式,然后在下边轮询ready fd列表。

简述 进程、线程、协程的区别 以及应用场景?

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。

协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

多线程:常见的浏览器、Web服务(现在写的web是中间件帮你完成了线程的控制),web处理请求,各种专用服务器(如游戏服务器)。

需要频繁创建销毁的优先用线程。

需要进行大量计算的优先使用线程(CPU频繁切换)。

多进程:目标子动能交互少,如果资源和性能许可,可以设计由多个子应用程序来组合完成目的。

1.进程是资源分配的最小单位,线程是CPU调度的最小单位。

2.进程是操作系统资源分配的单位。

3.线程是CPU调度的单位。

4.进程切换需要的资源最大,效率很低。

5.线程切换需要的资源一般,效率一般(当然在不考虑GIL的情况下)。

6.协程切换任务资源很小,效率高。

2.线程是指进程内的一个执行单元,也是进程内的可调度实体。线程与进程的区别

1.同一个进程中的线程共享同一内存空间,但是进程之间是独立的。

2.同一个进程中的所有线程的数据是共享的(进程通讯),进程之间的数据是独立的。

3.对主线程的修改可能会影响其他线程的行为,但是父进程的修改(除了删除以外)不会影响其他子进程。

4.一个进程至少有一个进程

5.同一个进程的线程之间可以直接通信,但是进程之间的交流需要借助中间代理(队列)来实现

6.创建新的线程很容易,但是创建新的进程需要对父进程做一次复制。

7.一个线程可以操作同一进程的其他线程,但是进程只能操作其子进程。

8.线程启动速度快,进程启动速度慢(但是两者运行速度没有可比性)。

3、协程与线程的比较

1. 一个线程可以多个协程,一个进程也可以单独拥有多个协程,这样python中则能使用多核CPU。

2. 线程进程都是同步机制,而协程则是异步。

3. 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态。

GIL是实现python解释器(CPython)时引入的一个概念,不是python特性。GIL是全局解释器锁,可以控制同一时刻只有一个线程能够运行,这样在跑多线程的情况下,只有当线程获取到全局解释器锁后才能运行,而全局解释器锁只有一个,因此即使在多核的情况下也只能发挥出单核的功能。另外在做IO操作时,GIL总是被释放。因此,IO密集型的python比计算密集型的程序更能利用多线程环境带来的便利。这对我们的程序究竟是选择多线程还是多进程大有帮助。

GIL锁是什么鬼?

我们所说的Python全局解释锁(GIL)简单来说就是一个互斥体(或者说锁),这样的机制只允许一个线程来控制Python解释器。

在IO密集型型操作下,多线程还是可以的。比如在网络通信,time.sleep()延时的时候。

在CPU密集型操作下,多线程性能反而不如单线程,此时只能用多进程。

Python中如何使用线程池和进程池?

进程池 multiprocessing.Pool

进程池 concurrent.futures.ProcessPoolExecutor

线程池 concurrent.futures.ThreadPoolExecutor

使用进程池来执行CPU密集型的任务,这样可以利用到多核的好处;使用线程池来处理IO型任务,根据实际情况来调整池的大小(线程过多时,切换线程的开销将会严重影响性能)。

threading.local的作用?

为每个线程创建一个独立的空间,使得线程对自己的空间中的数据进行操作(数据隔离)。

使用threading.local可以极大简化代码逻辑,同时保证各个子线程的数据安全。Threading.local最大的用处就是HTTP请求时绑定用户的信息,这样每个用户线程可以非常方便访问各自的资源而互不干扰。

进程之间如何进行通信?

IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC。

管道:速度慢,容量有限,只有父子进程能通讯。

FIFO:任何进程间都能通讯,但速度慢。

消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题

信号量:不能传递复杂消息,只能用来同步。

共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了同一进程内的一块内存。

什么是并发和并行?

解释一:并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。

解释二:并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。

解释三:在一台处理器上“同时”处理多个任务,在多台处理器上同时处理多个任务。如hadoop分布式集群。

并发编程的目标是充分的利用处理器的每一个核,以达到最高的处理性能。

进程锁和线程锁的作用?

线程锁:大家都不陌生,主要用来给方法、代码块加锁。当某个方法或者代码块使用锁时,那么在同一时刻至多仅有有一个线程在执行该段代码。当有多个线程访问同一对象的加锁方法/代码块时,同一时间只有一个线程在执行,其余线程必须要等待当前线程执行完之后才能执行该代码段。但是,其余线程是可以访问该对象中的非加锁代码块的。

进程锁:也是为了控制同一操作系统中多个进程访问一个共享资源,只是因为程序的独立性,各个进程是无法控制其他进程对资源的访问的,但是可以使用本地系统的信号量控制(操作系统基本知识)。

分布式锁:当多个进程不在同一个系统之中时,使用分布式锁控制多个进程对资源的访问。

解释什么是异步非阻塞?

同步和异步针对应用程序来,关注的是程序中间的协作关系;阻塞与非阻塞更关注的是单个进程的执行状态。

同步:执行一个操作之后,等待结果,然后才继续执行后续的操作。

异步:执行一个操作后,可以去执行其他的操作,然后等待通知再回来执行刚才没执行完的操作。

阻塞:进程给CPU传达一个任务之后,一直等待CPU处理完成,然后才执行后面的操作。

非阻塞:进程给CPU传达任我后,继续处理后续的操作,隔断时间再来询问之前的操作是否完成。这样的过程其实也叫轮询。

阻塞、非阻塞、多路IO复用,都是同步IO,异步必定是非阻塞的,所以不存在异步阻塞和异步非阻塞的说法。真正的异步IO需要CPU的深度参与。换句话说,只有用户线程在操作IO的时候根本不去考虑IO的执行全部都交给CPU去完成,而自己只等待一个完成信号的时候,才是真正的异步IO。所以,拉一个子线程去轮询、去死循环,或者使用select、poll、epool,都不是异步。

路由器和交换机的区别?

交换机工作在中继层,交换机根据MAC地址寻址,路由器工作在网络层,根据IP地址寻址,路由器可以处理TCP/IP协议,而交换机不可以等等。

什么是域名解析?

域名解析是把域名指向网站空间IP,让人们通过注册的域名可以方便地访问到网站一种服务。域名解析也叫域名指向、服务器设置、域名配置以及反向IP登记等等。说得简单点就是将好记的域名解析成IP,服务由DNS服务器完成,是把域名解析到一个IP地址,然后在此IP地址的主机上将一个子目录与域名绑定。

生产者消费者模型应用场景及优势?

处理场景:处理数据比较消耗时间,线程独占,生产数据不需要即时的反馈等。

应用于一个生产数据一个处理数据的场景 。

优势生产者和消费者之间不直接进行通信 而是通过一个队列相当于一个缓冲区,平衡了生产者和消费者的处理能力。

什么是cdn?

CDN节点解决了跨运营商和跨地域访问的问题,访问延时大大降低。

大部分请求在CDN边缘节点完成,CDN起到了分流作用,减轻了源站的负载。

浏览器本地缓存失效后,浏览器会向CDN边缘节点发起请求。类似浏览器缓存,CDN边缘节点也存在着一套缓存机制。

CDN的分流作用不仅减少了用户的访问延时,也减少的源站的负载。但其缺点也很明显:当网站更新时,如果CDN节点上数据没有及时更新,即便用户再浏览器使用Ctrl +F5的方式使浏览器端的缓存失效,也会因为CDN边缘节点没有同步最新数据而导致用户访问异常。

LVS是什么及作用?

LVS的英文全称是Linux Virtual Server,即Linux虚拟服务器。

LVS主要分为以下三部分:

Load Balancer 这是LVS的核心部分,它好比我们网站MVC模型的Controller。它负责将客户的请求按照一定的算法分发到下一层不同的服务器进行处理,自己本身不做具体业务的处理。另外该层还可用监控下一层的状态,如果下一层的某台服务器不能正常工作了,它会自动把其剔除,恢复后又可用加上。该层由一台或者几台Director Server组成。

Server Array 该层负责具体业务。可有WEB Server、mail Server、FTP Server、DNS Server等组成。注意,其实上层的Director Server也可以当Real server用的。

Shared Storage 主要是提高上一层数据和为上一层保持数据一致。

前面我们说了LVS是工作在网络层。相对于其它负载均衡的解决办法,比如DNS域名轮流解析、应用层负载的调度、客户端的调度等,它的效率是非常高的。LVS的通过控制IP来实现负载均衡。IPVS是其具体的实现模块。IPVS的主要作用:安装在Director Server上面,在Director Server虚拟一个对外访问的IP(VIP)。用户访问VIP,到达Director Server,Director Server根据一定的规则选择一个Real Server,处理完成后然后返回给客户端数据。这些步骤产生了一些具体的问题,比如如何选择具体的Real Server,Real Server如果返回给客户端数据等等。IPVS为此有三种机制:

VS/NAT(Virtual Server via Network Address Translation),即网络地址翻转技术实现虚拟服务器。当请求来到时,Diretor server上处理的程序将数据报文中的目标地址(即虚拟IP地址)改成具体的某台Real Server,端口也改成Real Server的端口,然后把报文发给Real Server。Real Server处理完数据后,需要返回给Diretor Server,然后Diretor server将数据包中的源地址和源端口改成VIP的地址和端口,最后把数据发送出去。由此可以看出,用户的请求和返回都要经过Diretor Server,如果数据过多,Diretor Server肯定会不堪重负。

VS/TUN(Virtual Server via IP Tunneling),即IP隧道技术实现虚拟服务器。它跟VS/NAT基本一样,但是Real server是直接返回数据给客户端,不需要经过Diretor server,这大大降低了Diretor server的压力。

VS/DR(Virtual Server via Direct Routing),即用直接路由技术实现虚拟服务器。跟前面两种方式,它的报文转发方法有所不同,VS/DR通过改写请求报文的MAC地址,将请求发送到Real Server,而Real Server将响应直接返回给客户,免去了VS/TUN中的IP隧道开销。这种方式是三种负载调度机制中性能最高最好的,但是必须要求Director Server与Real Server都有一块网卡连在同一物理网段上。

Nginx是什么及作用?

Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP代理服务器。

Nginx的作用是 反向代理,负载均衡。其特点是占有内存少,并发能力强。

keepalived是什么及作用?

keepalived是一个类似于Layer2,4,7交换机制的软件。是Linux集群管理中保证集群高可用的一个服务软件,其功能是用来防止单点故障。

keepalived是基于VRRP协议实现的保证集群高可用的一个服务软件,主要功能是实现真机的故障隔离和负载均衡器间的失败切换,防止单点故障。

haproxy是什么以及作用?

高可用性,负载平衡和用于TCP和基于http的应用程序的代理。

什么是负载均衡?

负载均衡是由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外供应效力而无须其他服务器的辅助。经过某种负载分管技术,将外部发送来的央求均匀分配到对称结构中的某一台服务器上,而接收到央求的服务器独登时回应客户的央求。均衡负载可以平均分配客户央求到服务器列阵,籍此供应快速获取重要数据,解决很多并发访问效力问题。这种群集技术可以用最少的出资取得接近于大型主机的性能。

什么是rpc及应用场景?

同步调用 客户方等待调用执行完成并返回结果。 异步调用 客户方调用后不用等待执行结果返回,但依然可以通过回调通知等方式获取返回结果。 若客户方不关心调用返回结果,则变成单向异步调用,单向调用不用返回结果。

RPC 的主要功能目标是让构建分布式计算(应用)更容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性。

简述 asynio模块的作用和应用场景。

asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。

asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。

简述 gevent模块的作用和应用场景。

当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。

由于切换是在IO操作时自动完成,所以gevent需要修改Python自带的一些标准库,这一过程在启动时通过monkey patch完成。

twisted框架的使用和应用?

Twisted是用Python实现的基于事件驱动的网络引擎框架,Twisted支持许多常见的传输及应用层协议,包括TCP、UDP、SSL/TLS、HTTP、IMAP、SSH、IRC以及FTP。就像Python一样,Twisted也具有“内置电池”(batteries-included)的特点。Twisted对于其支持的所有协议都带有客户端和服务器实现,同时附带有基于命令行的工具,使得配置和部署产品级的Twisted应用变得非常方便。

  • 发表于:
  • 原文链接:https://kuaibao.qq.com/s/20181225G1JLHB00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券