来源:https://www.nowcoder.com/feed/main/detail/af24b491b9cf45f788d77a0b4561e62c
七牛云后端实习面经
计算机网络
1、TCP/UDP区别?
- 连接性:
- TCP是面向连接的协议,通信双方在数据传输前需要建立连接,传输完成后需要释放连接。
- UDP是无连接的协议,通信双方在传输数据时不需要建立连接,也不需要释放连接。
- 可靠性:
- TCP提供可靠的数据传输,它通过序列号、确认应答和重传机制等方式保证数据的可靠性和完整性。
- UDP不提供可靠性保证,数据包可能会丢失或者乱序,不保证数据的可靠性和完整性。
- 数据包:
- TCP发送的数据是以数据流的形式进行传输的,没有数据边界,因此可以保证数据的顺序性和完整性。
- UDP发送的数据是以数据包的形式进行传输的,每个数据包是独立的,因此可能会出现乱序或丢失。
- 开销:
- TCP的连接管理和数据确认机制会增加一定的开销,因此在传输效率上可能略逊于UDP。
- UDP的开销相对较小,因为它不需要进行连接管理和数据确认,适合一些实时性要求较高的应用场景。
- 应用场景:
- TCP适用于对数据可靠性要求较高的应用,如文件传输、网页浏览等。
- UDP适用于对实时性要求较高、数据量较小、丢失少影响不大的应用,如音视频流媒体、在线游戏等。
2、TCP三次握手,四次挥手流程?
TCP三次握手建立连接的流程:
- 客户端向服务器发送连接请求:
- 客户端发送一个SYN(同步)标志位置为1的TCP数据包,以及一个随机的初始序列号(ISN)。
- 客户端进入SYN_SENT状态,等待服务器的确认。
- 服务器接收连接请求并回复:
- 服务器收到客户端的SYN包后,会返回一个确认应答,其中将SYN和ACK标志位置为1,同时也包含一个随机的初始序列号。
- 服务器进入SYN_RCVD状态,等待客户端的确认。
- 客户端发送确认:
- 客户端收到服务器的确认后,会再次发送一个确认,其中将ACK标志位置为1,同时确认号设置为服务器发送的序列号加1。
- 客户端和服务器都进入ESTABLISHED状态,连接建立完成,可以开始传输数据。
TCP四次挥手断开连接的流程:
客户端发送连接释放报文FIN:
客户端发送一个FIN标志位置为1的TCP数据包,表示客户端已经没有数据要发送了,但仍然可以接收数据。
服务器接收连接释放报文FIN,并回复确认:
服务器收到客户端的FIN后,会发送一个ACK确认报文,确认收到了客户端的FIN。
服务器发送连接释放报文FIN:
服务器发送一个FIN标志位置为1的TCP数据包,表示服务器也没有数据要发送了。
客户端接收连接释放报文FIN,并回复确认:
- 客户端收到服务器的FIN后,会发送一个ACK确认报文,确认收到了服务器的FIN。
- 客户端和服务器进入CLOSED状态,连接彻底关闭。
3、TCP为什么要三次握手,两次不行吗?
防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
如果只有两次握手,假设客户端发送的连接请求因网络问题延迟,但是连接请求最终到达了服务端,服务端接收到了连接请求并发送了确认,此时客户端并没有收到服务端的确认,由于网络问题,服务端的确认也没有到达客户端,客户端认为连接未建立。然后客户端重新发送连接请求,建立连接,但是服务端已经认为这是一个新的连接请求,于是建立了两个连接。这就导致了已失效的连接请求报文段突然又传送到了服务端,产生了错误。
防止已失效的连接请求报文段突然又传送到了客户端,因而产生错误。
类似于上述情况,如果只有两次握手,服务端发送的连接确认最终由于网络问题延迟到达客户端,但是客户端已经认为连接已经建立,于是开始传输数据。但是服务端并不知道连接已经建立,也就不会接收客户端发送的数据,这样就会导致数据的丢失。
防止服务器资源浪费。
通过三次握手,服务器可以确认客户端的确是有意向与其建立连接,从而避免了无效的连接请求对服务器资源的浪费。
4、为什么要四次挥手?
确保数据完整性:
在关闭连接之前,双方都可能还有数据需要发送,因此需要两次的FIN和ACK来确认彼此的数据已经发送完毕,才能最终关闭连接。
避免半关闭状态:
TCP是全双工通信,双方都可以同时发送和接收数据。在关闭连接时,需要确保双方都能正常完成数据的传输和接收,避免出现半关闭状态,即一方关闭了连接而另一方仍在发送数据。
保证可靠性:
TCP要求数据的可靠传输,四次挥手可以确保连接的可靠关闭,防止数据的丢失或不完整。
5、为什么要等待2MSL?
确保连接的彻底关闭:
在TCP连接的关闭过程中,有可能会出现最后一个ACK丢失的情况。如果在关闭连接后立即释放资源,而最后一个ACK丢失了,那么服务器将无法知道客户端已经收到了其发送的FIN,也就无法确定连接已经彻底关闭。因此,等待2MSL的时间,可以确保即使最后一个ACK丢失,也能够在一定时间内收到重发的ACK,从而保证连接的彻底关闭。
保证连接的唯一性:
等待2MSL的时间可以保证当前连接的所有报文段在网络中消失。这样可以确保下一个新的连接不会被之前的连接报文段混淆。
避免旧报文段对新连接的影响:
在网络中,可能会存在一些延迟、拥塞等问题,导致一些旧的报文段在网络中滞留。等待2MSL的时间可以确保之前的连接的所有报文段在网络中都已经被丢弃,避免对新连接产生影响。
6、如果客户端发生错误,服务器端会主动结束TCP连接吗?
在TCP协议中,如果客户端发生错误导致连接异常终止,通常情况下服务器端会检测到连接的异常,并主动关闭连接。这种情况下,服务器端会执行TCP的四次挥手过程来正常关闭连接。
客户端发生错误,服务器端的处理流程:
客户端异常终止:
如果客户端发生错误导致连接异常终止,例如客户端崩溃或者网络故障,客户端将无法继续发送数据或者接收数据,连接就会出现异常。
服务器端检测到异常:
服务器端会定期发送心跳包或者检测连接状态,如果服务器端在一定时间内没有收到客户端的响应或者确认,就会认为连接出现异常。
服务器端主动关闭连接:
- 服务器端检测到连接异常后,会立即或者在一段时间后(根据具体实现而定)发起TCP的四次挥手过程,正常关闭连接。
- 服务器端会发送一个FIN标志位置为1的TCP数据包,表示服务器端已经没有数据要发送了,但仍然可以接收数据。
- 客户端接收到服务器端的FIN后,会发送一个ACK确认报文,确认收到了服务器端的FIN。
- 客户端发送一个FIN标志位置为1的TCP数据包,表示客户端也没有数据要发送了。
- 服务器端接收到客户端的FIN后,会发送一个ACK确认报文,确认收到了客户端的FIN。
连接彻底关闭:
客户端和服务器端都进入CLOSED状态,连接彻底关闭,释放资源。
7、http和https的区别?
安全性:
- HTTP是明文传输的,数据在传输过程中是未加密的,可能被窃听和篡改。
- HTTPS通过SSL/TLS协议进行加密,可以确保数据在传输过程中的机密性和完整性,有效防止数据被窃听和篡改。
连接方式:
- HTTP默认使用80端口进行通信。
- HTTPS默认使用443端口进行通信。
证书:
- HTTPS需要服务器端使用SSL证书,用于验证服务器的身份,确保连接的安全性。
- HTTP不需要使用SSL证书。
性能:
HTTPS由于加密解密的过程会增加数据传输的时间和占用的CPU资源,因此可能会比HTTP略慢一些。
SEO:
Google搜索引擎在搜索排名时会更偏向于HTTPS网站,认为HTTPS网站更加安全可靠。
使用场景:
- HTTP适用于对安全性要求不高的场景,如普通的网页浏览、信息传输等。
- HTTPS适用于对数据安全性要求较高的场景,如在线支付、个人信息传输等。
C++
1、new和malloc的区别?
- 语法:
new是C++的关键字,直接调用new时,返回的是对象的指针。malloc是C标准库函数,调用时需要包含头文件<cstdlib>,返回的是void*类型的指针,需要进行强制类型转换。
- 类型安全:
new在分配内存时会调用对象的构造函数,可以自动执行对象的初始化。malloc只是简单地分配内存,不会调用任何构造函数,需要手动初始化分配的内存。
- 内存大小:
new操作符可以根据类型的大小自动计算所需的内存大小。malloc需要手动计算所需的内存大小,并传递给malloc函数。
- 返回值:
new操作符返回的是对象的指针,可以直接使用。malloc返回的是void*类型的指针,需要进行类型转换后才能使用。
- 异常处理:
new在分配内存失败时会抛出std::bad_alloc异常。malloc在分配内存失败时返回NULL,需要手动检查返回值来判断分配是否成功。
- 兼容性:
new是C++的关键字,不适用于C语言。malloc是C标准库函数,可以在C和C++中使用。
2、new的流程?
检查所需分配的内存大小:
在使用
new操作符时,编译器首先会根据类型的大小计算需要分配的内存大小。调用
operator new函数分配内存:new操作符会调用全局的operator new函数来分配内存。这个函数通常位于<new>头文件中,它会接收需要分配的内存大小作为参数,并返回分配的内存地址。调用构造函数进行初始化:
分配完内存后,
new操作符会调用对象的构造函数来初始化这块内存。如果是简单类型(如int、float等)的对象,构造函数会执行相应的初始化操作;如果是类类型的对象,构造函数会执行类的构造过程。返回指向对象的指针:
new操作符最终会返回指向分配的内存的指针,该指针指向的内存已经被初始化为一个对象。异常处理:
如果内存分配失败,
new操作符会抛出std::bad_alloc异常,表示内存分配失败。使用对象:
得到指向对象的指针后,可以使用该指针来访问和操作对象。
调用
operator delete函数释放内存:当对象不再需要时,应该使用
delete操作符来释放内存。delete操作符会调用operator delete函数来释放之前分配的内存。
3、堆和栈的区别?
- 分配方式:
- 栈是一种连续的内存空间,由操作系统自动分配和释放,用于存储函数的参数值、局部变量等。
- 堆是一种不连续的内存空间,由程序员手动分配和释放,用于存储动态分配的数据,如通过
new和malloc分配的内存。
- 分配效率:
- 栈的分配和释放由系统自动管理,分配和释放速度较快。
- 堆的分配和释放由程序员手动管理,分配和释放速度相对较慢。
- 大小限制:
- 栈的大小通常比较小,由系统限制,一般用于存储函数调用时的临时数据。
- 堆的大小通常比较大,受系统总体内存的限制,可以动态地申请和释放内存。
- 生命周期:
- 栈上的数据的生命周期由其所在函数的调用和返回决定,函数返回时,栈上的数据会自动释放。
- 堆上的数据的生命周期由程序员手动控制,需要手动释放,否则会造成内存泄漏。
- 碎片问题:
- 栈是连续的内存空间,不会出现内存碎片问题。
- 堆是不连续的内存空间,由于动态分配和释放,容易出现内存碎片问题。
- 数据存储:
- 栈上存储的是局部变量、函数参数等,是一种临时存储方式。
- 堆上存储的是动态分配的数据,需要手动管理其生命周期。
