面试之网络编程和并发

1、简述 OSI 七层协议。

物理层:主要基于电器特性发送高低电压(1、0),设备有集线器、中继器、双绞线等,单位:bit
数据链路层:定义了电信号的分组方式,设备:交换机、网卡、网桥,单位:帧
网络层:主要功能是将网络地址翻译成对应屋里地址,设备:路由
传输层:建立端口之间的通信,tcp、udp协议
会话层:建立客户端与服务端连接
表示层:对来自应用层的命令和数据进行解释,按照一定格式传给会话层。如编码、数据格式转换、加密解密、压缩解压
应用层:规定应用程序的数据格式

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

C/S架构:client端与server端的服务架构
B/S架构:隶属于C/S架构,Broswer端(网页端)与server端;
优点:统一了所有应用的入口,方便、轻量级

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

#三次握手:
1.客户端先向服务端发起一次询问建立连接的请求,并随机生成一个值作为标识
2.服务端向客户端先回应第一个标识,再重新发一个确认标识
3.客户端确认标识,建立连接,开始传输数据
#四次挥手:
1.客户端向服务端发起请求断开连接的请求
2.服务端向客户端确认请求
3.服务端向客户端发起断开连接请求
4.客户端向服务端确认断开请求

4、什么是arp协议?

# ARP(地址解析协议) 其主要用作将IP地址翻译为以太网的MAC地址
# 在局域网中,网络中实际传输的是“帧”,帧里面是有目标主机的MAC地址的。
# 在以太网中,一个主机要和另一个主机进行直接通信,必须要知道目标主机的MAC地址。

# 所谓“地址解析”就是主机在发送帧前将目标IP地址转换成目标MAC地址的过程。
# ARP协议的基本功能就是通过目标设备的IP地址,查询目标设备的MAC地址,以保证通信的顺利进行。

5、TCP和UDP的区别?

#TCP协议:面向连接
- 通信之前先三次握手
- 断开之前先四次握手
- 必须先启动服务端,再启动客户端-->连接服务端
- 安全、可靠、面向连接(不会丢包) 滑动窗口 流量控制 拥塞控制 慢开始 重传 
#UDP协议:无连接
- 传输速度快
- 先启动哪一端都可以
- 不面向连接,不能保证数据的完整性(如:QQ聊天)

6、什么是局域网和广域网?

局域网和广域网是按规模大小而划分的两种计算机网络。
# 范围在几千米以内的计算机网络统称为局域网(LAN、私网、内网);
# 而连接的范围超过10千米的,则称为广域网,因特网(Intenet)就是目前最大的广域网(WAN、公网、外网)。

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

因为TCP是面向连接的
通信之前先三次握手,通过握手,确保连接成功之后再通信
断开之前先四次挥手;双方互相确认之后再断开连接,这样一来保证了数据的安全、可靠,避免丢包

只要对方回了确认收到信息,才发下一个,如果没收到确认信息就重发

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

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

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

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

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

只有TCP有粘包现象,UDP永远不会粘包
粘包:在获取数据时,出现数据的内容不是本应该接收的数据,如:对方第一次发送hello,第二次发送world,
     我方接收时,应该收两次,一次是hello,一次是world,但事实上是一次收到helloworld,一次收到空,这种现象叫粘包

原因:粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。

什么情况会发生:

  1. 发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)
  2. 接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)

10、IO多路复用的作用?

# IO多路复用分为时间上的复用和空间上的复用,
# 空间上的复用是指将内存分为几部分,每一部分放一个程序,这样同一时间内存中就有多道程序;
# 时间上的复用是指多个程序需要在一个cpu上运行,不同的程序轮流使用cpu,
# 当某个程序运行的时间过长或者遇到I/O阻塞,操作系统会把cpu分配给下一个程序,
# 保证cpu处于高使用率,实现伪并发。

11、什么是防火墙以及作用?

# 防火墙?
防火墙是一个分离器,一个限制器,也是一个分析器,
有效地监控了内部网和Internet之间的任何活动,保证了内部网络的安全。
# 作用
防火墙可通过监测、限制、更改跨越防火墙的数据流,
尽可能地对外部屏蔽网络内部的信息、结构和运行状况,以此来实现网络的安全保护。

12、select、poll、epoll 模型的区别?

参考:IO模型

# 都是i/o多路复用的机制,监视多个socket是否发生变化,本质上都是同步i/o。因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的
# select,poll实现需要自己不断轮询所有监测对象,直到对象发生变化,在这个阶段中,可能要睡眠和唤醒多次交替,而epoll也需要调用epoll_wait不断轮询就绪链表,但是当对象发生变化时,会调用回调函数,将变化的对象放入就绪链接表中,并唤醒在epoll_wait中进入睡眠的进程。虽然都会睡眠和唤醒,但是select和poll在被唤醒的时候要遍历整个监测对象集合,而epoll只要判断就绪链表是否为空即可,节省了大量cpu的时间


FD(文件描述符)
select模型
优点:
    1:可移植性好,在某些Unix系统不支持poll()
    2:对于超时值提供了更好的精度:微妙,而poll是毫秒
select本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理。
缺点:
    1:最大并发数限制,因为一个进程所打开的 FD (文件描述符)是有限制的,由 FD_SETSIZE 设置,默认值是 1024/2048 ,因此 Select 模型的最大并发数就被相应限制了。
    2:效率问题,select每次调用都会线性扫描全部的FD集合,所以将FD_SETSIZE 改大,会越慢
    3:需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大。 

poll本质上和select 没有区别,它将用户传入的数组拷贝到内核空间,
它没有最大连接数的限制,原因是它基于链表来存储的但是同样有一个缺点:
大量的fd的数组被整体复制于用户态和内核地址空间,而不管这样的复制是不是有意义

# epoll支持水平触发和边缘触发,最大的特点在于边缘触发,
# 它只告诉进程哪些fd刚刚变为就需态,并且只会通知一次。

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

# 进程
进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。
# 线程
线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度
# 协程和线程的区别
协程避免了无意义的调度,由此可以提高性能;但同时协程也失去了线程使用多CPU的能力。

进程与线程的区别
(1)地址空间:线程是进程内的一个执行单位,进程内至少有一个线程,他们共享进程的地址空间,而进程有自己独立的地址空间
(2)资源拥有:进程是资源分配和拥有的单位,同一个进程内线程共享进程的资源
(3)线程是处理器调度的基本单位,但进程不是
(4)二者均可并发执行
(5)每个独立的线程有一个程序运行的入口

协程与线程
(1)一个线程可以有多个协程,一个进程也可以单独拥有多个协程,这样Python中则能使用多核CPU
(2)线程进程都是同步机制,而协程是异步
(3)协程能保留上一次调用时的状态

14、GIL锁是什么?

    GIL全局解释器锁(global interpreter lock),每个线程在执行时候都需要先获取GIL,保证同一时刻只有一个线程可以执行代码,即同一时刻只有一个线程使用CPU,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。也就是说多线程并不是真正意义上的同时执行。
    对于io密集型任务,python的多线程起到作用,但对于cpu密集型任务,python的多线程几乎占不到任何优势,还有可能因为争夺资源而变慢。解决办法就是多进程和协程(协程也只是单CPU,但是能减小切换代价提升性能).
    GIL保护的是解释器级的数据,保护用户自己的数据则需要自己加锁处理

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

进程池:就是在一个进程内控制一定个数的线程
基于concurent.future模块的进程池和线程池 (他们的同步执行和异步执行是一样的)

16、threading.local的作用?

a.threading.local
作用:为每个线程开辟一块空间进行数据存储。
问题:自己通过字典创建一个类似于threading.local的东西。
storage = {
   4740: {val: 0},
   4732: {val: 1},
   4731: {val: 3},
}

b.自定义Local对象
作用:为每个线程(协程)开辟一块空间进行数据存储。
try:
   from greenlet import getcurrent as get_ident
except Exception as e:
   from threading import get_ident
from threading import Thread
import time
class Local(object):
   def __init__(self):
      object.__setattr__(self, 'storage', {})
   def __setattr__(self, k, v):
      ident = get_ident()
      if ident in self.storage:
         self.storage[ident][k] = v
      else:
         self.storage[ident] = {k: v}
   def __getattr__(self, k):
      ident = get_ident()
      return self.storage[ident][k]
obj = Local()
def task(arg):
   obj.val = arg
   obj.xxx = arg
   print(obj.val)
for i in range(10):
   t = Thread(target=task, args=(i,))
   t.start()

17、进程之间如何进行通信?

# 进程间通讯有多种方式,包括信号,管道,消息队列,信号量,共享内存,socket等

18、什么是并发和并行?

# 并发:同一时刻只能处理一个任务,但一个时段内可以对多个任务进行交替处理(一个处理器同时处理多个任务)
# 并行:同一时刻可以处理多个任务(多个处理器或者是多核的处理器同时处理多个不同的任务)
# 类比:并发是一个人同时吃三个馒头,而并行是三个人同时吃三个馒头。

19、进程锁和线程锁的作用?

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

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

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

20、解释什么是异步非阻塞?

'非阻塞':遇到IO阻塞不等待(setblooking=False),(可能会报错->捕捉异常)
- sk=socket.socket()
- sk.setblooking(False)
'异步':回调(ajax),当达到某个指定状态之后,自动调用特定函数

21、路由器和交换机的区别?

'交换机'
用于在同一网络内数据快速传输转发,工作在数据链路层;
通过MAC寻址,不能动态划分子网;
只能在一条网络通路中运行,不能动态分配。

'路由器'
是一个网关设备,内部局域网到公网的一个关卡;
工作在网络层;
通过IP寻址,可以划分子网;
可以在多条网络通道中运行,可以动态分配IP地址。

'简单说'
交换机就是把一根网线变成多根网线;
路由器就是把一个网络变成多个网络;
如果不上外网,只是局域网,交换机即可;
如果上外网,并且给网络划分不同网段,就必须用路由器。

22、什么是域名解析?DNS

# 在网上,所有的地址都是ip地址,但这些ip地址太难记了,所以就出现了域名(比如http://baidu.com)。
# 而域名解析就是将域名,转换为ip地址的这样一种行为。
# 例如:访问www.baidu.com,实质是把域名解析成IP。

23、如何修改本地hosts文件?

'hosts':
Hosts就是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”
可以用来屏蔽一些网站,或者指定一些网站(修改hostsFQ)
'修改':
# windows:位置:C:\Windows\System32\drivers\etc
# linux:位置:/etc/hosts

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

生产者与消费者模式是通过一个容器来解决生产者与消费者的强耦合关系,生产者与消费者之间不直接进行通讯,
而是利用阻塞队列来进行通讯,生产者生成数据后直接丢给阻塞队列,消费者需要数据则从阻塞队列获取,
实际应用中,生产者与消费者模式则主要解决生产者与消费者生产与消费的速率不一致的问题,达到平衡生产者与消费者的处理能力,而阻塞队列则相当于缓冲区。

应用场景:用户提交订单,订单进入引擎的阻塞队列中,由专门的线程从阻塞队列中获取数据并处理

优势:
1;解耦
假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。
将来如果消费者的代码发生变化,可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。
2:支持并发
生产者直接调用消费者的某个方法,还有另一个弊端。由于函数调用是同步的(或者叫阻塞的),在消费者的方法没有返回之前,生产者只能一直等着。而使用这个模型,生产者把制造出来的数据只需要放在缓冲区即可,不需要等待消费者来取
3:支持忙闲不均
缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。
当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。等生产者的制造速度慢下来,消费者再慢慢处理掉。

25、什么是cdn?

# 用户获取数据时,不需要直接从源站获取,通过CDN对数据分发
# 用户可以从一个较优的服务器获取数据,从而达到快速访问,并减少源站负载压力的目的。

26、LVS是什么及作用?

LVS :Linux虚拟服务器
作用:LVS主要用于多服务器的负载均衡。
它工作在网络层,可以实现高性能,高可用的服务器集群技术。
它廉价,可把许多低性能的服务器组合在一起形成一个超级服务器。
它易用,配置非常简单,且有多种负载均衡的方法。
它稳定可靠,即使在集群的服务器中某台服务器无法正常工作,也不影响整体效果。另外可扩展性也非常好。

27、Nginx是什么及作用?

Nginx是一个轻量级、高性能、稳定性高、并发性好的HTTP和反向代理服务器。

28、keepalived是什么及作用?

Keepalived是Linux下一个轻量级别的高可用解决方案。
高可用,其实两种不同的含义:广义来讲,是指整个系统的高可用行,狭义的来讲就是之主机的冗余和接管,

29、haproxy是什么以及作用?

HAProxy提供高可用性、负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。
HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在当前的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架中,同时可以保护你的web服务器不被暴露到网络上。

30、什么是负载均衡?

负载均衡有两方面的含义:
# 首先,大量的并发访问或数据流量分担到多台节点设备上分别处理,减少用户等待响应的时间;
# 其次,单个重负载的运算分担到多台节点设备上做并行处理,每个节点设备处理结束后,将结果汇总,返回给用户,系统处理能力得到大幅度提高。

31、什么是rpc及应用场景?

RPC 的全称是 Remote Procedure Call 是一种进程间通信方式。
它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。
即程序员无论是调用本地的还是远程的,本质上编写的调用代码基本相同(例如QQ远程操作)

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

asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。
asyncio的异步操作,需要在coroutine中通过yield from完成。

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

Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,
在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。
Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。

34、twisted框架的使用和应用?

Twisted是一个事件驱动型的网络模型。
事件驱动模型编程是一种范式,这里程序的执行流由外部决定。
特点是:包含一个事件循环,当外部事件发生时,使用回调机制来触发相应的处理。

网络链接过程中的状态

面试之网络编程和并发_第1张图片

  • - CLOSED:无连接是活动的或正在进行
  • - LISTEN:服务器在等待进入呼叫
  • - SYN_RECV:一个连接请求已经到达,等待确认
  • - SYN_SENT:应用已经开始,打开一个连接
  • - ESTABLISHED:正在通信,正常数据传输状态
  • - FIN_WAIT1:主动方发送第一次fin之后保持的状态
  • - FIN_WAIT2:主动方接受到被动方返回的ack,但是还未收到被动方发送的fin
  • - TIME_WAIT:主动收到被动方发送的fin同时发送ack之后的状态,等待超时结束的请求数
  • - CLOSING:两边同时尝试关闭
  • - LAST_ACK:等待所有分组死掉

 

你可能感兴趣的:(面试)