Advertisement

服务器面试必备-网络知识点整理

阅读量:

服务器或者运维开发在面试中几乎都不能逃避被问到网络相关的问题,因为网络在服务器开发中是实现客户端与服务器之间通信、数据传输、分布式计算以及安全性和访问控制的重要工具。了解网络的原理和技术对于服务器开发人员来说是非常重要的。因此这篇文章我将一些常用面试题整理出来,分享给大家,有兴趣的可以订阅专栏获得更多的学习机会。

1、什么是IO多路复用

I/O多路复用是一种用于同时监听多个IO流的机制。在传统的IO模型中,每个IO流需要一个独立的线程或进程来处理,而IO多路复用则允许一个线程或进程同时监听多个IO流,从而提高系统的并发能力和性能。

常见的IO多路复用机制有select、poll和epoll。这些机制使用了操作系统提供的特定函数,通过将多个IO流注册到一个特定的事件循环中,然后轮询这些IO流的状态变化,从而实现对多个IO流的监听。

在IO多路复用机制中,当有一个或多个IO流就绪时,系统会通知应用程序,应用程序可以立即对就绪的IO流进行读取或写入操作,而不需要阻塞等待。这样可以减少系统的阻塞时间,提高系统的并发能力和性能。

2.HTTP 的特点?HTTP 有哪些缺点?

HTTP 的特点概括灵活可扩展 主

要体现在两个方面。
一个是语义上的自由,只规定了基本格式,比如空格分隔单词,换行分隔字段,其他的各个部分都没有严格的语法限制
另一个是传输形式的多样性,不仅仅可以传输文本,还能传输图片、视频等任意数据,非常方便。
可靠传输 HTTP 基于 TCP/IP,因此把这一特性继承了下来。这属于 TCP 的特性,不具体介绍了。
请求-应答 也就是一发一收、有来有回, 当然这个请求方和应答方不单单指客户端和服务器之间,如果某台服务器作为代理来连接后端的服务端,那么这台服务器也会扮演请求方的角色。
无状态 这里的状态是指通信过程的上下文信息,而每次 http 请求都是独立、无关的,默认不需要保留状态信息

HTTP 缺点

无状态 所谓的优点和缺点还是要分场景来看的,对于 HTTP 而言,最具争议的地方在于它的无状态。
在需要长连接的场景中,需要保存大量的上下文信息,以免传输大量重复的信息,那么这时候无状态就是 http 的缺点了。
但与此同时,另外一些应用仅仅只是为了获取一些数据,不需要保存连接上下文信息,无状态反而减少了网络开销,成为了 http 的优点。
明文传输 即协议里的报文(主要指的是头部)不使用二进制数据,而是文本形式。这当然对于调试提供了便利,但同时也让 HTTP 的报文信息暴露给了外界,给攻击者也提供了便利。WIFI陷阱就是利用 HTTP 明文传输的缺点,诱导你连上热点,然后疯狂抓你所有的流量,从而拿到你的敏感信息。
队头阻塞问题 当 http 开启长连接时,共用一个 TCP 连接,同一时刻只能处理一个请求,那么当前请求耗时过长的情况下,其它的请求只能处于阻塞状态,也就是著名的队头阻塞问题。

3、epool中et和lt的区别与实现原理

LT:水平触发,效率会低于ET触发,尤其在大并发,大流量的情况下。但是LT对代码编写要求比较低,不容易出现问题。LT模式服务编写上的表现是:只要有数据没有被获取,内核就不断通知你,因此不用担心事件丢失的情况。
ET:边缘触发,效率非常高,在并发,大流量的情况下,会比LT少很多epoll的系统调用,因此效率高。但是对编程要求高,需要细致的处理每个请求,否则容易发生丢失事件的情况。

4、tcp连接建立的时候3次握手,断开连接的4次握手的具体过程

三次握手 --- 第一次握手是客户端connect连接到server,server accept client的请求之后,向client端发送一个消息,相当于说我都准备好了,你连接上我了,这是第二次握手,第3次握手就是client向server发送的,就是对第二次握手消息的确认。之后client和server就开始通讯了。

四次握手 --- 断开连接的一端发送close请求是第一次握手,另外一端接收到断开连接的请求之后需要对close进行确认,发送一个消息,这是第二次握手,发送了确认消息之后还要向对端发送close消息,要关闭对对端的连接,这是第3次握手,而在最初发送断开连接的一端接收到消息之后,进入到一个很重要的状态time_wait状态,这个状态也是面试官经常问道的问题,最后一次握手是最初发送断开连接的一端接收到消息之后。对消息的确认。

5、connect方法会阻塞,请问有什么方法可以避免其长时间阻塞?

最通常的方法最有效的是加定时器;也可以采用非阻塞模式。
或者考虑采用异步传输机制,同步传输与异步传输的主要区别在于同步传输中,如果调用recvfrom后会一致阻塞,从而导致调用线程暂停;异步传输机制则不然,会立即返回。

6.如何理解 HTTP 的请求方法?

http/1.1 规定了以下请求方法(注意,都是大写):

  • GET 通常用来获取资源
  • HEAD 获取资源的元信息
  • POST 提交数据,即上传数据
  • PUT 修改数据
  • DELETE 删除资源(几乎用不到)
  • CONNECT 建立连接隧道,用于代理服务器
  • OPTIONS 列出可对资源实行的请求方法,预检请求,用来跨域请求
  • TRACE 追踪请求-响应的传输路径

7.HTTPS 是如何建立连接的?其间交互了什么?

SSL/TLS 协议基本流程:
1.TCP 三次同步握手
2.客户端向服务器索要并验证服务器的公钥
3.双方协商生产「会话秘钥」
4.SSL 安全加密隧道协商完成
5.双方采用「会话秘钥」进行加密通信。
2,3步是 SSL/TLS 的建立过程,也就是握手阶段 SSL/TLS 的握手阶段涉及四次通信

8.对于定长和不定长的数据,HTTP 是怎么传输的?

定长包体

对于定长包体而言,发送端在传输的时候一般会带上 Content-Length, 来指明包体的长度。我们用一个nodejs服务器来模拟一下:

复制代码
 const http = require('http');

    
  
    
 const server = http.createServer();
    
  
    
 server.on('request', (req, res) => {
    
   if(req.url === '/') {
    
     res.setHeader('Content-Type', 'text/plain');
    
     res.setHeader('Content-Length', 10);
    
     res.write("helloworld");
    
   }
    
 })
    
  
    
 server.listen(8081, () => {
    
   console.log("成功启动");
    
 })
    
    
    
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/cHyxi7mpYTNbqBJgd3zFI4tQaM2f.png)

启动后访问: localhost:8081。浏览器中显示如下:

复制代码
    helloworld
    
    

这是长度正确的情况,那不正确的情况是如何处理的呢?我们试着把这个长度设置的小一些:

复制代码
    res.setHeader('Content-Length', 8);
    
    

重启服务,再次访问,现在浏览器中内容如下:

复制代码
    hellowor
    
    

那后面的ld哪里去了呢?实际上在 http 的响应体中直接被截去了。然后试着将这个长度设置得大一些:

复制代码
    res.setHeader('Content-Length', 12);
    
    

此时浏览器显示如下:

60cc8ee927ba

直接无法显示了。可以看到 Content-Length 对于 http 传输过程起到了十分关键的作用,如果设置不当可以直接导致传输失败。

不定长包体

上述是针对于定长包体,那么对于不定长包体而言是如何传输的呢?这里就必须介绍另外一个 http 头部字段了:

复制代码
 Transfer-Encoding: chunked

    
  
    
 // Transfer-Encoding: chunked
    
 // Transfer-Encoding: compress
    
 // Transfer-Encoding: deflate
    
 // Transfer-Encoding: gzip
    
 // Transfer-Encoding: identity
    
 // Several values can be listed, separated by a comma
    
 // Transfer-Encoding: gzip, chunked
    
    
    
    

表示分块传输数据,设置这个字段后会自动产生两个效果:

  • Content-Length 字段会被忽略
  • 基于长连接持续推送动态内容 我们依然以一个实际的例子来模拟分块传输,nodejs 程序如下:
复制代码
 const http = require('http');

    
  
    
 const server = http.createServer();
    
  
    
 server.on('request', (req, res) => {
    
   if(req.url === '/') {
    
     res.setHeader('Content-Type', 'text/html; charset=utf8');
    
     res.setHeader('Content-Length', 10);
    
     res.setHeader('Transfer-Encoding', 'chunked');
    
     res.write("<p>来啦</p>");
    
     setTimeout(() => {
    
       res.write("第一次传输<br/>");
    
     }, 1000);
    
     setTimeout(() => {
    
       res.write("第二次传输");
    
       res.end()
    
     }, 2000);
    
   }
    
 })
    
  
    
 server.listen(8009, () => {
    
   console.log("成功启动");
    
 })
    
    
    
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/5wJLKcYqoHa3zv0nBWMEli64dIp9.png)
66412b848c5d

用 telnet 抓到的响应如下:

5580cefd2818

注意,Connection: keep-alive 及之前的为响应行和响应头,后面的内容为响应体,这两部分用换行符隔开。响应体的结构比较有意思,如下所示:

复制代码
 chunk长度(16进制的数)

    
 第一个chunk的内容
    
 chunk长度(16进制的数)
    
 第二个chunk的内容
    
 ......
    
 0
    
    
    
    

最后是留有有一个空行的,这一点请大家注意。以上便是 http 对于定长数据和不定长数据的传输方式。

9.TCP协议如何保证可靠传输

1.应用数据被分割成 TCP 认为最适合发送的数据块。
2.TCP 给发送的每一个包进行编号,接收方对数据包进行排序,把有序数据传送给应用层。
3.校验和: TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。
4.流量控制: TCP 连接的每一方都有固定大小的缓冲空间,TCP的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协议。 (TCP 利用滑动窗口实现流量控制)
5.拥塞控制: 当网络拥塞时,减少数据的发送。
6.ARQ协议: 也是为了实现可靠传输的,它的基本原理就是每发完一个分组就停止发送,等待对方确认。在收到确认后再发下一个分组。
7.超时重传: 当 TCP 发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。
8.TCP 的接收端会丢弃重复的数据。

10.HTTP长连接,短连接

在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源(如JavaScript文件、图像文件、CSS文件等),每遇到这样一个Web资源,浏览器就会重新建立一个HTTP会话。 而从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:

复制代码
    Connection:keep-alive
    
    

在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接需要客户端和服务端都支持长连接。 HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。

11、网络中,如果客户端突然掉线或者重启,服务器端怎么样才能立刻知道?

若客户端掉线或者重新启动,服务器端会收到复位信号,每一种tcp/ip得实现不一样,控制机制也不一样。

12.HTTP 如何处理大文件的传输?

对于几百 M 甚至上 G 的大文件来说,如果要一口气全部传输过来显然是不现实的,会有大量的等待时间,严重影响用户体验。因此,HTTP 针对这一场景,采取了范围请求的解决方案,允许客户端仅仅请求一个资源的一部分。

如何支持

当然,前提是服务器要支持范围请求,要支持这个功能,就必须加上这样一个响应头:

复制代码
 $ curl -I https://www.yuque.com/

    
 HTTP/1.1 200 OK
    
 ...
    
 Accept-Ranges: bytes
    
 Content-Length: 146515
    
  
    
  
    
 $ curl -I http://download.dcloud.net.cn/HBuilder.9.0.2.macosx_64.dmg
    
 $ curl -H  "Range: bytes=0-10" http://download.dcloud.net.cn/HBuilder.9.0.2.macosx_64.dmg -v
    
  
    
 //省略
    
 HTTP/1.1 200 OK
    
 ...
    
 Accept-Ranges: none
    
  
    
 //详细的
    
 HTTP/1.1 200 OK
    
 Server: Tengine
    
 Content-Type: application/octet-stream
    
 Content-Length: 233295878
    
 Connection: keep-alive
    
 Date: Mon, 26 Apr 2021 13:12:46 GMT
    
 x-oss-request-id: 6086BC4E66D721363972F4A8
    
 x-oss-cdn-auth: success
    
 Accept-Ranges: bytes
    
 ETag: "6D932737FD8C6058D6AE93BCC4C74AA7-45"
    
 Last-Modified: Tue, 06 Mar 2018 13:20:31 GMT
    
 x-oss-object-type: Multipart
    
 x-oss-hash-crc64ecma: 7369427768111114923
    
 x-oss-storage-class: Standard
    
 x-oss-server-time: 156
    
 Ali-Swift-Global-Savetime: 1617704046
    
 Via: cache15.l2cn1809[0,200-0,H], cache2.l2cn1809[1,0], cache7.cn682[39,39,200-0,M], cache2.cn682[44,0]
    
 Age: 778
    
 X-Cache: MISS TCP_MISS dirn:-2:-2
    
 X-Swift-SaveTime: Mon, 26 Apr 2021 13:25:44 GMT
    
 X-Swift-CacheTime: 3600
    
 Timing-Allow-Origin: *
    
 EagleId: af062a4216194435440612604e
    
    
    
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/YgO80tzsQWa6FdxGrJLjIA52y9BU.png)

假如在响应中存在Accept-Ranges首部(并且它的值不为 “none”),那么表示该服务器支持范围请求 在上面的响应中,Accept-Ranges: bytes 表示界定范围的单位是 bytes 。这里 Content-Length也是有效信息,因为它提供了要检索的图片的完整大小

如果站点未发送Accept-Ranges首部,那么它们有可能不支持范围请求。一些站点会明确将其值设置为 "none",以此来表明不支持。在这种情况下,某些应用的下载管理器会将暂停按钮禁用。

复制代码
 curl -I https://www.youtube.com/watch?v=EwTZ2xpQwpA

    
  
    
 HTTP/1.1 200 OK
    
 ...
    
 Accept-Ranges: none
    
    
    
    

Range 字段拆解

而对于客户端而言,它需要指定请求哪一部分,通过 Range 这个请求头字段确定,格式为bytes=x-y。接下来就来讨论一下这个 Range 的书写格式:

0-499 表示从开始到第 499 个字节。

500- 表示从第 500 字节到文件终点。

-100 表示文件的最后100个字节。

服务器收到请求之后,首先验证范围是否合法,如果越界了那么返回416错误码,否则读取相应片段,返回206状态码。同时,服务器需要添加 Content-Range 字段,这个字段的格式根据请求头中Range字段的不同而有所差异。具体来说,请求单段数据和请求多段数据,响应头是不一样的。举个例子:

复制代码
 // 单段数据

    
 curl http://i.imgur.com/z4d4kWk.jpg -i -H "Range: bytes=0-1023"
    
 Range: bytes=0-9
    
  
    
 // 多段数据
    
 curl http://www.example.com -i -H "Range: bytes=0-50, 100-150"
    
 Range: bytes=0-9, 30-39
    
    
    
    

接下来就分别来讨论着两种情况

单段数据

对于单段数据的请求,返回的响应如下:

复制代码
 HTTP/1.1 206 Partial Content

    
 Content-Length: 10
    
 Accept-Ranges: bytes
    
 Content-Range: bytes 0-9/100
    
  
    
 i am xxxxx
    
    
    
    

值得注意的是Content-Range字段,0-9表示请求的返回,100表示资源的总大小,很好理解。

多段数据

接下来看看多段请求的情况。得到的响应会是下面这个形式:

复制代码
 HTTP/1.1 206 Partial Content

    
 Content-Type: multipart/byteranges; boundary=00000010101
    
 Content-Length: 189
    
 Connection: keep-alive
    
 Accept-Ranges: bytes
    
  
    
  
    
 --00000010101
    
 Content-Type: text/plain
    
 Content-Range: bytes 0-9/96
    
  
    
 i am xxxxx
    
 --00000010101
    
 Content-Type: text/plain
    
 Content-Range: bytes 20-29/96
    
  
    
 eex jspy e
    
 --00000010101--
    
    
    
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/qKOTjm7W2gBvQzoEH5d3UVFbk0fX.png)

这个时候出现了一个非常关键的字段Content-Type: multipart/byteranges;boundary=00000010101,它代表了信息量是这样的:

请求一定是多段数据请求

响应体中的分隔符是 00000010101

因此,在响应体中各段数据之间会由这里指定的分隔符分开,而且在最后的分隔末尾添上--表示结束。以上就是 http 针对大文件传输所采用的手段。

与分块传输编码的对比

Transfer-Encoding 首部允许分块编码,这在数据量很大,并且在请求未能完全处理完成之前无法知晓响应的体积大小的情况下非常有用。服务器会直接把数据发送给客户端而无需进行缓冲或确定响应的精确大小——后者会增加延迟。范围请求与分块传输是兼容的,可以单独或搭配使用

13、TTL是什么?有什么用处,通常那些工具会用到它?(ping? traceroute? ifconfig? netstat?)

简: TTL是Time To Live,一般是hup count,每经过一个路由就会被减去一,如果它变成0,包会被丢掉。它的主要目的是防止包在有回路的网络上死转,浪费网络资源。ping和traceroute用到它。
详: TTL是Time To Live,目前是hup count,当包每经过一个路由器它就会被减去一,如果它变成0,路由器就会把包丢掉。IP网络往往带有环(loop),比如子网A和子网B有两个路由器相连,它就是一个loop。TTL的主要目的是防止包在有回路的网络上死转,因为包的TTL最终后变成0而使得此包从网上消失(此时往往路由器会送一个ICMP包回来,traceroute就是根据这个做的)。ping会送包出去,所以里面有它,但是ping不一定非要不可它。traceroute则是完全因为有它才能成的。ifconfig是用来配置网卡的,netstat -rn 是用来列路由表的,所以都用不着它

14.说说 HTTP1.1 相比 HTTP1.0 提高了什么性能?

HTTP1.1 相比 HTTP1.0 性能上的改进:

  • 使用 TCP 长连接的方式改善了 HTTP/1.0 短连接造成的性能开销。
  • 支持 管道(pipeline)网络传输,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。

但 HTTP1.1 还是有性能瓶颈:

  • 请求/响应头部(Header)未经压缩就发送,首部信息越多延迟越大。只能压缩 Body 的部分
  • 发送冗长的首部。每次互相发送相同的首部造成的浪费较多
  • 服务器是按请求的顺序响应的,如果服务器响应慢,会招致客户端一直请求不到数据,也就是队头阻塞;
  • 没有请求优先级控制
  • 请求只能从客户端开始,服务器只能被动响应

15.HTTP 与 HTTPS 有哪些区别?

  • HTTP 是超文本传输协议,信息是明文传输,存在安全风险的问题。HTTPS 则解决 HTTP 不安全的缺陷,在 TCP 和 HTTP 网络层之间加入了 SSL/TLS 安全协议,使得报文能够加密传输。
  • HTTP 连接建立相对简单, TCP 三次握手之后便可进行 HTTP 的报文传输。而 HTTPS 在 TCP 三次握手之后,还需进行SSL/TLS 的握手过程,才可进入加密报文传输。
  • HTTP 的端口号是 80,HTTPS 的端口号是 443。
  • HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的

16、网络编程中设计并发服务器,使用多进程 与 多线程 ,请问有什么区别?

答案一:

1)进程:子进程是父进程的复制品。子进程获得父进程数据空间、堆和栈的复制品。
2)线程:相对与进程而言,线程是一个更加接近与执行体的概念,它可以与同进程的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
两者都可以提高程序的并发度,提高程序效率和响应时间。
线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源管理和保护;而进程正相反。同时,线程适合于在SMP机器上,而进程则可以跨机器迁移。

答案二:

根本区别就一点:用多进程每个进程有自己的地址空间(address space),线程则共享地址空间。所有其它区别都是由此而来的:
1)速度:线程产生的速度快,线程间的通讯快、切换快等,因为他们在同一个地址空间内。
2)资源利用率:线程的资源利用率比较好也是因为他们在同一个地址空间内。
3)同步问题:线程使用公共变量/内存时需要使用同步机制还是因为他们在同一个地址空间内。

17、网络编程的一般步骤

对于TCP连接:

1.服务器端1)创建套接字create;2)绑定端口号bind;3)监听连接listen;4)接受连接请求accept,并返回新的套接字;5)用新返回的套接字recv/send;6)关闭套接字。
2.客户端1)创建套接字create; 2)发起建立连接请求connect; 3)发送/接收数据send/recv;4)关闭套接字。

TCP总结:

Server端:create -- bind -- listen-- accept-- recv/send-- close
Client端:create------- conncet------send/recv------close.

对于UDP连接:

1.服务器端:1)创建套接字create;2)绑定端口号bind;3)接收/发送消息recvfrom/sendto;4)关闭套接字。
2.客户端:1)创建套接字create;2)发送/接收消息sendto/recvfrom;3)关闭套接字.

UDP总结:

Server端:create----bind ----recvfrom/sendto----close
Client端:create---- sendto/recvfrom----close.

18、TCP的重发机制是怎么实现的?

1)滑动窗口机制,确立收发的边界,能让发送方知道已经发送了多少(已确认)、尚未确认的字节数、尚待发送的字节数;让接收方知道(已经确认收到的字节数)。
2)选择重传,用于对传输出错的序列进行重传。

19、TCP为什么不是两次连接?而是三次握手?

如果A与B两个进程通信,如果仅是两次连接。可能出现的一种情况就是:A发送完请报文以后,由于网络情况不好,出现了网络拥塞,即B延时很长时间后收到报文,即此时A将此报文认定为失效的报文。B收到报文后,会向A发起连接。此时两次握手完毕,B会认为已经建立了连接可以通信,B会一直等到A发送的连接请求,而A对失效的报文回复自然不会处理。依次会陷入B忙等的僵局,造成资源的浪费。

20、socket编程,如果client断电了,服务器如何快速知道?

使用定时器(适合有数据流动的情况); 使用socket选项SO_KEEPALIVE(适合没有数据流动的情况);

21、fork()一子进程程后 父进程癿全局变量能不能使用?

fork后子进程将会拥有父进程的几乎一切资源,父子进程的都各自有自己的全局变量。不能通用,不同于线程。对于线程,各个线程共享全局变量。

22、4G的long型整数中找到一个最大的,如何做?

要找到最大的肯定要遍历所有的数的,而且不能将数据全部读入内存,可能不足。算法的时间复杂度肯定是O(n)
感觉就是遍历,比较。。。。还能怎么改进呢????
可以改进的地方,就是读入内存的时候,一次多读些。。。。
需要注意的就是每次从磁盘上尽量多读一些数到内存区,然后处理完之后再读入一批。减少IO次数,自然能够提高效率。而对于类快速排序方法,稍微要麻烦一些: 分批读入,假设是M个数,然后从这M个数中选出n个最大的数缓存起来,直到所有的N个数都分批处理完之后,再将各批次缓存的n个数合并起来再进行一次类快 速排序得到最终的n个最大的数就可以了。在过程中,如果缓存数太多,可以不断地将多个缓存合并,保留这些缓存中最大的n个数即可。由于类快速排序的时 间复杂度是O(N),这样分批处理再合并的办法,依然有极大的可能会比堆和败者树更优。当然,在空间上会占用较多的内存。

此题还有个变种,就是寻找K个最大或者最小的数。有以下几种算法:
容量为K的最大堆/最小堆,假设K可以装入内存;
如果N个数可以装入内存,且都小于MAX,那么可以开辟一个MAX大的数组,类似计数排序。。。从数组尾部扫描K个最大的数,头部扫描K个最小的数。

23、tcp三次握手的过程,accept发生在三次握手哪个阶段?

client 的 connect 引起3次握手
server 在socket, bind, listen后,阻塞在accept,三次握手完成后,accept返回一个fd,因此accept发生在三次握手之后。

24、tcp流, udp的数据报,之间有什么区别,为什么TCP要叫做数据流?

TCP本身是面向连接的协议,S和C之间要使用TCP,必须先建立连接,数据就在该连接上流动,可以是双向的,没有边界。所以叫数据流 ,占系统资源多
UDP不是面向连接的,不存在建立连接,释放连接,每个数据包都是独立的包,有边界,一般不会合并。
TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证

25、socket在什么情况下可读?

  1. 接收缓冲区有数据,一定可读
  2. 对方正常关闭socket,也是可读
  3. 对于侦听socket,有新连接到达也可读
    4.socket有错误发生,且pending

26、TCP通讯中,select到读事件,但是读到的数据量是0,为什么,如何解决?

select 返回0代表超时。select出错返回-1。
select到读事件,但是读到的数据量为0,说明对方已经关闭了socket的读端。本端关闭读即可。
当select出错时,会将接口置为可读又可写。这时就要通过判断select的返回值为-1来区分。

27、说说IO多路复用优缺点?

IO多路复用优点:

1.相比基于进程的模型给程序员更多的程序行为控制。
2.IO多路复用只需要一个进程就可以处理多个事件,单个进程内数据共享变得容易,调试也更容易。
3.因为在单一的进程上下文当中,所以不会有多进程多线程模型的切换开销。

IO多路复用缺点:

1.业务逻辑处理困难,编程思维不符合人类正常思维。
2.不能充分利用多核处理器。

28、说说select机制的缺点

每次调用select,都需要把监听的文件描述符集合fd_set从用户态拷贝到内核态,从算法角度来说就是O(n)的时间开销。

每次调用select调用返回之后都需要遍历所有文件描述符,判断哪些文件描述符有读写事件发生,这也是O(n)的时间开销。

内核对被监控的文件描述符集合大小做了限制,并且这个是通过宏控制的,大小不可改变(限制为1024)。

29、说一下epoll的好处

epoll解决了select和poll在文件描述符集合拷贝和遍历上的问题,能够在一个进程当中监听多个文件描述符,并且十分高效。

30、epoll的实现知道么?在内核当中是什么样的数据结构进行存储,每个操作的时间复杂度是多少?

epoll是Linux系统中提供的一种高效的I/O多路复用机制。其基于事件驱动的模型,可以有效地管理大量的并发连接。

在内核中,epoll使用一个红黑树(RB Tree)来存储所有的事件。这个红黑树是通过一个特殊的数据结构epoll_event来表示的,每个epoll_event对应一个文件描述符和其上感兴趣的事件。

每次调用epoll_wait函数,内核都会检查红黑树中的所有事件,并返回已经就绪(满足条件)的事件集合。而如果没有任何事件就绪,调用epoll_wait将一直阻塞,直到有事件就绪为止。

对于epoll的操作时间复杂度如下:

  • 创建红黑树的时间复杂度为O(1);
  • 添加或修改事件的时间复杂度为O(log n),其中n为红黑树中事件的个数;
  • 删除事件的时间复杂度为O(k log n),其中k为要删除的事件的个数;
  • 查询已经就绪事件的时间复杂度为O(log n + m),其中n为红黑树中事件的个数,m为已就绪事件的个数。

总体来说,epoll提供了高效的I/O多路复用机制,可以帮助开发者管理大量的并发连接,并在事件就绪时迅速进行相应的操作。

全部评论 (0)

还没有任何评论哟~