奇安信C++后端面经,问的很奇怪!(上)

本文涉及的产品
数据传输服务 DTS,数据迁移 small 3个月
推荐场景:
MySQL数据库上云
数据传输服务 DTS,数据同步 small 3个月
推荐场景:
数据库上云
数据传输服务 DTS,数据同步 1个月
简介: 奇安信C++后端面经,问的很奇怪!

大家好,我是深度Linux在这个“金秋十月”,也是一个收获的季节。各大公司在这个时候都陆续开奖了,特别是前几天团子的开奖,还是超出了很多人的预期。
当然,几家欢喜几家愁,都没关系,因为找工作本来就是一个战线较长的任务。尽管你现在只有小公司offer,或者0offer,其实都没有必要焦虑。你只管做你的,好好进行复盘总结,面过的,就好好复盘面经,没面过的,就好好学基础知识,刷算法题,再加上持续性的投递,你一定会有满意的offer!

1、简单介绍一下webserver

Web服务器是一种软件或应用程序,负责接收客户端请求并向其提供相应的资源。它充当客户端和后端服务器之间的中介,通过HTTP协议进行通信。

Web服务器的主要功能包括:

  1. 接受和处理客户端请求:Web服务器监听指定的端口,接受来自客户端(例如浏览器)发送的HTTP请求。它解析请求,识别所需资源,并采取适当的操作来响应请求。
  2. 资源管理:Web服务器负责管理和提供各种资源,如HTML文件、图像、CSS样式表、JavaScript脚本等。它能够从磁盘上的文件系统中获取这些资源,并将其发送给客户端。
  3. 处理动态内容:除了静态资源外,Web服务器还可以与后台应用程序(如CGI脚本、PHP脚本、ASP.NET等)交互以生成动态内容。它可以将请求转发给适当的后台处理程序,并将生成的结果返回给客户端。
  4. 连接管理:Web服务器需要管理并保持与多个客户端之间的连接。它可以使用不同的策略来处理连接池、线程池或事件驱动等方式来高效地处理并发请求。
  5. 安全性和身份验证:为了保护网站和数据安全,Web服务器通常具有各种安全功能,如HTTPS支持、SSL证书配置、身份验证和访问控制等。
  6. 日志记录:Web服务器可以记录每个请求的详细信息,包括访问时间、客户端IP地址、请求路径、响应状态等。这些日志对于分析和监视网站流量以及故障排除非常有用。

常见的Web服务器软件包括Apache HTTP Server、Nginx、Microsoft IIS等。它们在性能、可靠性和扩展性方面都有不同的特点,开发人员可以根据实际需求选择适合自己项目的Web服务器。

2、这个webserver并发连接多少

这个取决于具体的web server的实现和配置。一般来说,web server可以通过多线程、多进程或异步IO等方式处理并发连接。不同的实现方式和硬件环境都会对并发连接数产生影响。有些服务器可以处理成千上万个并发连接,而另一些可能只能处理几百个。因此,并发连接数是相对灵活可调的,取决于特定情况下所使用的服务器架构和配置。

3、线程池和线程个数怎么设置

置线程池的大小需要考虑多个因素,包括系统资源、任务类型和负载情况等。以下是一些常见的设置原则:

  1. CPU核心数:通常线程池的大小应该与CPU核心数相近或略大,这样可以最大程度地利用CPU资源。
  2. 任务类型和执行时间:如果任务属于I/O密集型,即涉及到等待外部资源(如网络请求、文件读写等),可以设置较大的线程池来充分利用CPU空闲时间。而对于计算密集型任务,由于存在CPU竞争,适当减少线程池大小可能更有效。
  3. 内存限制:每个线程都需要一定的内存开销,在确定线程池大小时要考虑系统可用内存。避免过多线程导致内存耗尽和频繁的内存交换。
  4. 平均负载:根据当前系统平均负载情况动态调整线程池大小。例如使用指标如CPU利用率、请求处理速度等来监控系统负载,根据阈值自动调整线程池大小。

总体来说,合理地设置线程池大小可以提高程序性能和资源利用率。但要注意避免过度设置导致资源浪费或系统性能下降。

4、线程模型怎么搭配epoll进行使用

在线程模型中,可以使用epoll作为事件驱动的I/O多路复用机制,以提高服务器的并发性能。

一种常见的搭配方式是,使用一个主线程负责监听新连接,并将新连接分配给工作线程处理。具体步骤如下:

  1. 创建一个epoll实例,并设置感兴趣的事件类型(如可读事件)。
  2. 在主线程中创建监听套接字,并将其加入到epoll实例中。
  3. 进入循环,调用epoll_wait()函数等待事件发生。
  4. 当有新连接到来时,在主线程中接收连接请求,并根据一定的策略选择一个空闲的工作线程。
  5. 将新连接的套接字添加到该工作线程的epoll实例中,并设置相应的回调函数或处理逻辑。
  6. 工作线程从自己所属的epoll实例中获取就绪事件,并执行相应的操作(如读取数据、处理业务逻辑等)。
  7. 回到第3步,继续等待新事件。

这样,通过将连接分配给不同的工作线程进行处理,可以提高系统对并发请求的处理能力。

需要注意以下几点:

  • 主线程只负责监听新连接,不直接处理具体请求。工作线程才是真正处理业务逻辑和响应客户端请求的地方。
  • 每个工作线程都需要拥有自己的epoll实例,以避免竞争和阻塞。每个工作线程独立负责处理自己所分配的连接。
  • 在具体实现时,还需考虑连接管理、线程池、数据同步等方面的细节。

以上是一种常见的搭配方式,根据实际情况和需求,也可以选择其他线程模型(如多线程、异步IO等)结合epoll使用。

5、怎么理解io多路复用

O多路复用是一种通过同时监听多个IO事件的机制,使得一个进程能够同时处理多个IO请求。它利用操作系统提供的select、poll、epoll等函数,在一个线程内监听多个文件描述符(socket)上是否有数据可读或可写,从而避免了使用多线程或多进程来处理并发IO请求的开销。

通过IO多路复用,可以将大量的网络连接集中到少数几个线程或进程上进行管理和处理,提高了系统的并发性能。当某个文件描述符就绪时(例如有数据可读),应用程序会得到通知并可以立即对其进行读取操作,这样就能更高效地利用CPU资源。

6、epoll的边沿触发和水平触发

在Linux中,epoll是一种高效的I/O事件通知机制。它提供了两种触发模式:边沿触发(Edge Triggered)和水平触发(Level Triggered)。

边沿触发(Edge Triggered)模式:

  • 当文件描述符上有可读/可写事件发生时,只会触发一次通知。
  • 如果不立即处理该事件,下次调用epoll_wait()时将不再返回该事件,直到有新的事件再次发生。
  • 边缘触发适合于非阻塞的、以消息为单位进行处理的场景。

水平触发(Level Triggered)模式:

  • 当文件描述符上有可读/可写事件发生时,如果没有处理完全部数据,下次调用epoll_wait()时仍然会返回该事件。
  • 直到该文件描述符上没有待处理的数据或者被关闭才不再返回该事件。
  • 水平触发适合于阻塞式的、基于流的传输协议,如TCP。

选择使用边沿触发还是水平触发取决于具体场景和应用需求。一般来说,在高并发且非阻塞的网络服务器中,边缘触发能够更好地控制事件通知频率和减少无效循环检查。而对于普通应用程序或者阻塞式的IO操作,水平触发则是更常见和常用的模式。

7、你两种模式都使用过,那两种使用起来有什么区别吗

边沿触发(Edge Triggered)模式和水平触发(Level Triggered)模式是在事件驱动系统中常见的两种触发方式。

区别如下:

  1. 边沿触发模式:当输入信号从低电平变为高电平或从高电平变为低电平时,会产生一个触发事件。只有在状态改变瞬间才会触发事件。例如,边沿触发模式可用于处理硬件中断信号。
  2. 水平触发模式:只要输入信号保持在指定的电平上,就会持续触发事件。无论输入信号处于何种状态,只要满足条件就会持续触发事件。例如,在网络编程中,水平触发模式可用于处理socket数据的读取。

总体而言,边沿触发更适合处理瞬时状态变化的场景,而水平触发则更适合连续性地监测和响应特定状态。

8、有观察过这两种的区别从连接到传数据(没有)

边沿触发(Edge Triggered)和水平触发(Level Triggered)是指在数字电子系统中用于触发事件的不同方式。

在边沿触发模式下,只有在输入信号的状态从低电平到高电平或者从高电平到低电平的瞬间时,才会产生触发事件。换句话说,只有在信号变化的边沿时刻才会被触发。

而在水平触发模式下,只要输入信号保持为高电平或者低电平状态,就会持续地产生触发事件。无论输入信号是否有变化,在达到预设的水平时都会触发事件。

区别主要体现在连接和传输数据方面:

  1. 连接:对于边沿触发模式,通常需要一个外部时钟或者专门的边沿检测器来检测输入信号的变化,并将结果传递给系统。而水平触发模式则可以直接使用输入信号作为事件的条件。
  2. 传输数据:在边沿触发模式下,当边沿变化时才会进行数据传输。而在水平触发模式下,一旦满足了预设条件,数据传输就会立即开始。

9、有观察过http的包吗(没有)

是的,我可以观察和解析HTTP的包。HTTP(Hypertext Transfer Protocol)是一种用于在Web浏览器和Web服务器之间传输数据的协议。通过分析HTTP包,我们可以了解请求和响应的头部信息、请求方法、URL、状态码等内容,以及实际传输的数据。这对于网络调试、安全分析和性能优化都非常有用。

10、有看过http的报文的头吗(回答了一下对应的头的内容)

HTTP报文的头部包含了一些重要的信息。通常有以下几个常见的头字段:

  1. 请求行:包含了请求方法(GET、POST等)、URI路径和HTTP协议版本。
  2. 响应行:包含了响应状态码和对应的状态描述。
  3. 请求头:包含了客户端向服务器发送请求时附带的各种信息,例如User-Agent、Accept、Content-Type等。
  4. 响应头:包含了服务器返回给客户端的响应相关信息,例如Server、Content-Type、Content-Length等。
  5. 实体头:包含了实体主体部分(可选)的附加信息,例如Content-Encoding、Last-Modified等。

通过解析这些报文头部可以获得请求或响应的相关信息,以便进行适当的处理和解析。

11、除了Get和post其他方法见过吗(没有)

除了常见的GET和POST方法,还有一些其他HTTP请求方法,例如:

  1. PUT:用于创建或更新资源。通常用于向服务器发送数据,并将其存储在指定的URI下。
  2. DELETE:用于删除指定的资源。
  3. PATCH:用于部分更新资源。与PUT不同,PATCH仅对资源进行部分更改。
  4. HEAD:类似于GET请求,但只返回响应头信息,而不返回实际内容。
  5. OPTIONS:获取目标URL所支持的通信选项。

这些是HTTP协议中常见的一些请求方法。具体使用哪个方法取决于你要实现的功能和服务端的支持情况。

12、get和post有什么区别吗

GET和POST是HTTP协议中两种常用的请求方法,它们在以下几个方面有区别:

1. 参数传递方式:GET请求通过URL参数传递数据,参数会附加在URL的末尾;而POST请求将数据放在请求体中进行传递,不会显示在URL上。

2. 数据大小限制:由于GET请求将参数暴露在URL上,因此对于数据大小有限制。而POST请求没有明确的大小限制,可以传递大量的数据。

3. 安全性:由于GET请求参数直接暴露在URL上,所以相对来说比较不安全,容易被拦截和篡改。POST请求把参数放在请求体中,相对更安全一些。

4. 缓存机制:GET请求默认可缓存结果,浏览器会缓存返回的页面或资源;而POST请求默认不可缓存。

13、URL组成,uri是什么

URL(Uniform Resource Locator)是统一资源定位符的缩写,它是用来标识和定位互联网上资源的字符串。一个完整的URL通常包括以下几个部分:

  1. 协议(Protocol):指示要使用的传输协议,如HTTP、HTTPS、FTP等。
  2. 主机名(Hostname):表示资源所在的主机或服务器的名称。
  3. 端口号(Port number):可选项,指定访问服务器时所使用的端口号,默认根据协议自动确定。
  4. 路径(Path):指示服务器上特定资源的路径或位置。
  5. 查询参数(Query parameters):可选项,用于传递额外的参数给服务器。
  6. 锚点(Anchor):可选项,在HTML中使用锚点进行页面内导航。

URI(Uniform Resource Identifier)是统一资源标识符的缩写,它是一个用来唯一标识和引用某个资源的字符串。URI包括两种形式:

  1. URL(Uniform Resource Locator),可以被用来直接访问并获取某个资源;
  2. URN(Uniform Resource Name),仅用于标识资源而不提供直接访问。

因此,URI是URL和URN的总称。

15、线程池用到那些线程间通讯

线程池通常使用以下几种线程间通讯方式:

  1. 任务队列(Task Queue):线程池中的线程从任务队列中获取待执行的任务。通过将任务放入任务队列,可以实现生产者-消费者模型,在多个线程之间传递任务。
  2. 线程同步机制:在多个工作线程同时处理任务时,可能需要使用互斥锁、条件变量等线程同步机制来保证数据的一致性和避免竞态条件。
  3. 回调函数(Callback):当一个任务完成后,可以通过回调函数将结果返回给调用方或者通知其他相关的模块。
  4. 线程间信号量(Thread Synchronization Primitives):通过信号量等同步原语,可以实现多个线程之间的协调与控制。
  5. 共享内存(Shared Memory):多个线程可以通过共享内存来进行数据交换,但需要注意对共享数据的访问控制,以避免竞态条件。

这些通讯方式可以帮助线程池中的线程协作执行任务,并且能够有效地管理和分配工作负载。具体使用哪种通讯方式取决于应用程序的需求和设计。

16、C++类型转化

在C++中,类型转换可以通过以下方式进行:

  1. 隐式类型转换(Implicit Conversion):在不需要显式指定的情况下,编译器会自动进行类型转换。例如,将一个整数赋值给浮点数类型变量时,编译器会自动进行从整型到浮点型的隐式转换。
  2. 显式类型转换(Explicit Conversion):有时需要手动指定将一个数据类型转换为另一个数据类型。C++提供了几种显式类型转换操作符:
  • static_cast:用于执行静态类型检查的转换,在合理范围内允许不同但相关的数据类型之间的转换。
  • dynamic_cast:用于执行安全向下造型(downcasting),主要用于基类和派生类之间的转换。
  • const_cast:用于去除常量属性或添加常量属性。
  • reinterpret_cast:一种底层强制类型转换,通常用于将指针或引用重新解释为其他指针或引用。

注意,在使用显式类型转换时,请确保转换是安全且符合语义逻辑。错误的使用可能导致运行时错误或未定义行为。

17、C++中的堆和栈的区别

在C++中,堆(Heap)和栈(Stack)是两种不同的内存分配方式,它们有以下区别:

  1. 分配方式:栈上的变量是通过系统自动进行分配和释放的,而堆上的内存则需要手动进行分配和释放。
  2. 内存管理:栈内存由编译器自动管理,它会在变量超出作用域时自动释放。而堆内存需要手动分配和释放,在不再使用时必须显式地调用 delete 或 delete[] 进行回收。
  3. 大小限制:栈通常比较小,并且大小固定。而堆则没有固定大小限制,可以动态地分配所需大小的内存空间。
  4. 访问速度:由于栈上的变量是连续分配的,因此访问速度相对较快。而堆上的内存分散在各个地址上,访问速度相对较慢。
  5. 生命周期:栈上的变量生命周期受到作用域控制,当离开作用域时会自动销毁。而堆上的对象在手动释放之前一直存在。

18、指针和引用的区别

指针和引用是C++中的两个重要概念,它们都可以用于间接访问对象或变量。下面是它们的区别:

  1. 定义和使用方式:指针使用*来声明和解引用,而引用使用&来声明,不需要解引用。
  2. 空值:指针可以为空(nullptr),表示没有指向任何对象或变量,而引用必须始终引用有效的对象。
  3. 可变性:指针本身可以重新赋值为另一个地址,即改变所指向的对象或变量;而引用一旦初始化后就不能再改变所引用的对象。
  4. 对象关系:指针可以指向多个不同类型的对象,并且可以通过运算符修改所指向对象的值;而引用始终与特定类型的对象相关联,并且无法更改为引用其他类型的对象。
  5. 空间占用:通常情况下,指针需要占据内存空间来存储地址信息;而引用本质上只是原对象的一个别名,并不需要额外的空间。

19、关键字static的使用

关键字 "static" 在 C++ 中有多种用法,以下是其中几个常见的用法:

1.静态变量(Static Variables):在函数内部声明的静态变量具有静态生存期,即它们在整个程序执行期间都存在,并且只会初始化一次。例如:

void foo() {
   static int count = 0; // 静态局部变量
   count++;
   cout << "Count: " << count << endl;
}

2.静态成员变量(Static Member Variables):静态成员变量属于类本身而不是类的实例,并且在所有类对象之间共享。例如:

class MyClass {
public:
   static int sharedVariable; // 静态成员变量声明
};

int MyClass::sharedVariable = 10; // 静态成员变量定义

int main() {
   cout << MyClass::sharedVariable << endl; // 访问静态成员变量
   return 0;
}

3.静态成员函数(Static Member Functions):静态成员函数属于类本身而不是类的实例,可以直接通过类名来调用,而不需要创建对象实例。例如:

class MyClass {
public:
   static void myStaticFunction() {
       cout << "This is a static member function." << endl;
   }
};

int main() {
   MyClass::myStaticFunction(); // 调用静态成员函数
   return 0;
}

除了以上几种用法,"static" 还可以用于限制变量或函数的作用域为当前文件(称为内部链接)以及在类模板中声明静态数据成员等。具体使用取决于上下文和需求。

20、webserver出现bug的debug思路

当一个Web服务器出现bug时,以下是一些常见的debug思路:

  1. 检查日志:查看服务器日志文件,特别是错误日志,以获取有关bug的更多信息。日志通常会记录请求和响应的详细信息,包括错误消息和异常堆栈跟踪。
  2. 排查输入数据:检查传递给服务器的输入数据,包括HTTP请求参数、表单数据等。验证输入数据是否符合预期,并确保它们正确解析和处理。
  3. 分步调试:使用适当的调试工具,在代码中设置断点并逐步执行程序,观察变量值的变化以及程序流程。这可以帮助您找到可能引发bug的特定代码段。
  4. 异常处理:确保适当地捕获和处理异常。对于抛出异常的部分进行详细调试,并尝试理解异常触发的原因。
  5. 代码审查:仔细审查代码逻辑、函数调用和算法实现。检查潜在的逻辑错误、边界情况和不恰当的函数使用。
  6. 环境配置检查:确认所需软件库和依赖项是否正确安装和配置。有时,问题可能与环境相关,例如缺少必要的依赖项或不正确的配置文件。
  7. 测试用例编写:编写针对各种情况的测试用例,包括正常情况和边界条件。这有助于重现bug,并确认修复是否成功。
  8. 借助工具:使用适当的工具进行性能分析、内存泄漏检测或代码覆盖率分析等。这些工具可以帮助您找到隐藏的问题或优化性能。

21、gdb使用过吗,调试过多线程吗

在使用gdb调试多线程程序时,你可以按照以下步骤进行操作:

  1. 使用编译选项 -g 编译你的程序,以便生成调试信息。
  2. 在终端中运行 gdb your_program 命令启动gdb,并加载你的可执行文件。
  3. 运行 set follow-fork-mode child 命令设置跟踪子进程。
  4. 运行 break main 命令设置一个断点在主函数入口处(或者其他你希望设置断点的地方)。
  5. 运行 run 命令启动程序执行,当程序停在断点处时,表示已经开始调试。
  6. 使用 thread 命令切换到指定线程进行调试。可以使用 info threads 查看当前所有线程的信息和ID。
  7. 可以使用常见的gdb命令如 nextstepprint 等来逐步执行代码,并查看变量值等信息。

注意事项:

  • 多线程调试可能会涉及并发问题,请小心处理共享数据访问和同步问题。
  • 在不同线程之间切换时,需要保证正在被切换到的线程是处于暂停状态。

这些是基本的操作步骤,具体根据你的实际情况和需求进行调整和扩展。

22、linux上ping命令能确认那些内容

在Linux上,使用ping命令可以确认以下内容:

  1. 目标主机的可达性:通过发送ICMP Echo请求,ping命令会等待目标主机的回应。如果能够收到回应,则说明目标主机是可达的;否则,表示目标主机不可达。
  2. 往返延迟时间(RTT):ping命令会显示往返延迟时间,也就是从发送请求到接收响应所经过的时间。通过观察RTT可以评估网络的延迟情况。
  3. 数据包丢失率:ping命令还会显示数据包丢失率,即发送的请求中未收到响应的比例。高丢包率可能表示网络连接存在问题。
  4. TTL(Time to Live)值:每个发送出去的ICMP Echo请求都带有一个TTL值,在经过路由器时逐渐减小。当TTL为0时,路由器将丢弃该数据包并返回一个“Time Exceeded”错误消息。
  5. 网络拓扑分析:通过连续向不同IP地址发送ping请求,并观察结果,可以获取一些关于网络拓扑结构和路由路径方面的信息。

这些是ping命令常用来确认的内容,在诊断网络连接和故障排查时非常有用。

23、ping的底层实现

Ping是一种网络诊断工具,用于测试主机之间的连通性。在底层实现上,Ping使用ICMP协议(Internet Control Message Protocol)来发送探测包并接收目标主机的响应。

具体而言,Ping的底层实现可以分为以下几个步骤:

  1. 创建一个原始套接字(Raw Socket)。
  2. 构建ICMP报文,其中包括类型字段(通常为8表示请求Echo Request,或0表示回复Echo Reply)、校验和字段、标识符、序列号等信息。
  3. 设置IP头部信息,包括源IP地址和目标IP地址。
  4. 计算校验和,并将ICMP报文发送到目标主机。
  5. 等待目标主机响应,如果收到相应的Echo Reply报文,则表示目标主机可达;如果超时未收到响应,则表示目标主机不可达。
  6. 根据收到的响应时间计算往返时间(Round Trip Time, RTT),并显示或记录结果。

需要注意的是,具体操作系统或平台上对Ping命令的实现可能有所差异,但基本原理都是通过ICMP协议进行网络连通性测试。

24、C++中map,如果key不存在,使用[]形式遍历能成功吗

在C++中,使用[]操作符形式访问一个map时,如果key不存在,会自动创建该key,并将其与一个默认值关联起来。因此,遍历一个map并使用[]形式访问时,如果key不存在,会在该位置插入新的键值对。请注意,在使用[]操作符访问时要确保map是可写的(非const)。

25、tcp编程常用的api

在C/C++中,进行TCP编程常用的API包括:

  1. socket():创建套接字
  2. bind():将套接字绑定到一个地址和端口
  3. listen():监听传入的连接请求
  4. accept():接受传入的连接请求并返回新的套接字
  5. connect():建立与远程服务器的连接
  6. send()/sendto():发送数据到已连接或未连接的套接字
  7. recv()/recvfrom():从已连接或未连接的套接字接收数据
  8. close():关闭套接字

这些是基本的TCP编程API,可以使用它们来实现TCP服务器和客户端程序

26、tcp三次握手、四次挥手

TCP三次握手(Three-way Handshake)是建立TCP连接的过程,具体步骤如下:

  1. 客户端向服务器发送一个SYN报文段,指示请求建立连接,并选择一个初始序列号。
  2. 服务器收到SYN报文段后,回复客户端一个SYN+ACK报文段,表示同意建立连接,并选择自己的初始序列号。
  3. 客户端收到服务器的SYN+ACK报文段后,再向服务器发送一个ACK报文段,确认连接建立。此时双方可以开始正式传输数据。

TCP四次挥手(Four-way Handshake)是关闭TCP连接的过程,具体步骤如下:

  1. 主动关闭方(一般是客户端)发送一个FIN报文段给被动关闭方(一般是服务器),表示要关闭连接。
  2. 被动关闭方收到FIN报文段后,回复一个ACK报文段进行确认。
  3. 被动关闭方进入TIME_WAIT状态,在等待一段时间(一般为两个最大报文生存时间)后才能彻底关闭连接。
  4. 主动关闭方收到ACK报文段后,也进入CLOSED状态。此时连接已经完全关闭。

这样通过三次握手建立连接和四次挥手断开连接,确保了可靠的数据传输和双方对连接状态的准确掌握。

27、输入一个url会出现那些过程

当你输入一个URL(统一资源定位符),通常会经历以下过程:

  1. DNS解析:计算机将URL中的域名解析为对应的IP地址,以便进行网络通信。
  2. 建立TCP连接:使用IP地址与服务器建立TCP连接,确保可靠的数据传输。
  3. 发送HTTP请求:发送HTTP请求报文给服务器,包含请求方法(GET、POST等)、路径、头部信息和可能的请求体。
  4. 服务器处理请求:服务器接收到请求后,根据路径找到相应的资源,并执行相关处理逻辑。
  5. 返回HTTP响应:服务器将处理结果封装成HTTP响应报文返回给客户端。响应报文包含状态码、头部信息和响应体(可能是HTML、图片、JSON等)。
  6. 客户端渲染:客户端接收到响应后,根据响应内容进行页面渲染或其他操作。如果是网页,则浏览器会解析HTML、CSS和JavaScript,并呈现出最终的页面效果。

28、写服务器碰到过死锁吗

死锁在服务器开发中是一个常见的问题。死锁指的是多个线程或进程因为相互等待对方所持有的资源而陷入无限等待的状态。在服务器编程中,使用多线程或多进程处理并发请求时,如果不正确地管理锁和资源,就容易导致死锁情况的发生。

解决死锁问题可以采取以下几种方法:

  1. 避免使用过多的锁:减少并发操作所需要的锁数量,尽量简化代码逻辑。
  2. 使用良好的锁策略:合理选择和管理锁,在保证数据安全性的前提下尽量减小临界区范围。
  3. 按顺序获取锁:确保每个线程按照相同的顺序获取锁,避免出现循环等待情况。
  4. 设置超时时间:为每个请求设置合理的超时时间,并在超时后释放所有占用资源,防止长时间阻塞导致整体性能下降。
  5. 使用专门工具进行分析:借助死锁检测工具来识别和解决潜在的死锁问题。

注意,在服务器开发中预防和解决死锁问题需要综合考虑系统架构、并发设计、线程安全等方面,以确保系统的稳定性和性能。

29、http和https的区别

HTTP(Hypertext Transfer Protocol)和HTTPS(Hypertext Transfer Protocol Secure)是用于在Web浏览器和服务器之间传输数据的两种协议。

  1. 安全性:最显著的区别是安全性。HTTP不加密数据传输,而HTTPS通过使用SSL(Secure Sockets Layer)或TLS(Transport Layer Security)协议对数据进行加密来保护数据的安全性。
  2. 端口号:HTTP默认使用端口号80进行通信,而HTTPS默认使用端口号443进行通信。
  3. 数据传输方式:HTTP的数据传输是明文的,可以被拦截并查看内容。而HTTPS通过加密技术保护数据传输,使得拦截者无法轻易解读或修改传输的内容。
  4. 证书要求:为了建立HTTPS连接,服务器需要具有数字证书。这个证书由受信任的证书颁发机构(CA)签发,以确认服务器身份和公钥的有效性。

30、https的认证是谁认证谁

在 HTTPS 中,认证是由第三方机构颁发的数字证书来实现的。这个机构通常被称为证书颁发机构(Certificate Authority,CA)。当网站使用 HTTPS 时,它需要向证书颁发机构申请数字证书。证书颁发机构会对网站进行验证,并签发包含公钥及其他信息的数字证书。当用户访问这个网站时,浏览器会检查该数字证书是否有效并且与域名匹配。如果验证通过,则建立安全连接。如果数字证书无效或不可信,则浏览器会给出警告提示。

因此,HTTPS 认证是由受信任的第三方机构(即证书颁发机构)对网站的身份进行认证,并确保通信过程中数据传输的安全性和完整性。

还不熟悉的朋友,这里可以先领取一份Linux c/c++开发新手学习资料包(入坑不亏):

【后端开发】

  1. 编程基本功扎实,掌握 C/C++/JAVA 等开发语言、常用算法和数据结构;
  2. 熟悉 TCP/UDP 网络协议及相关编程、进程间通讯编程;
  3. 了解 Python、Shell、Perl 等脚本语言;
  4. 了解 MYSQL 及 SQL 语言、编程,了解 NoSQL, key-value 存储原理;
  5. 全面、扎实的软件知识结构,掌握操作系统、软件工程、设计模式、数据结构、数据库系统、网络安全等专业知识;
  6. 了解分布式系统设计与开发、负载均衡技术,系统容灾设计,高可用系统等知识。


这里给大家推荐零声教育全网独家的【Linux C/C++开发】课程体系,通过原理技术+源码分析+案例分析+项目实战,全面解析Linux C/C++,8个上线项目,2W+行手写代码,全面解析:

Linux C/C++开发

1、精进基石专栏

(一)数据结构与算法

  • 随处可见的红黑树
  • 红黑树的应用场景进程调度cfs,内存管理
  • 红黑树的数学证明与推导
  • 手撕红黑树的左旋与右旋
  • 红黑树添加的实现与添加三种情况的证明
  • 红黑树删除的实现与删除四种情况的证明
  • 红黑树的线程安全的做法
  • 分析红黑树工程实用的特点
  • 磁盘存储链式的B树与B+树
  • 磁盘结构分析与数据存储原理
  • 多叉树的运用以及B树的定义证明
  • B树插入的两种分裂
  • B树删除的前后借位与节点合并
  • 手撕B树的插入,删除,遍历,查找
  • B+树的定义与实现
  • B+树叶子节点的前后指针
  • B+树的应用场景与实用特点
  • B+树的线程安全做法
  • 海量数据去重的abhloriter bitap
  • hash的原理与hash函数的实现
  • hash的应用场景
  • 分布式hash的实现原理
  • 海量数据去重布隆过滤器
  • 布隆过滤的数学推导与证明

(二)设计模式

  • 创建型设计模式
  • 单例模式
  • 策略模式
  • 观察者模式
  • 工厂方法模式与抽象工厂模式
  • 原型模式
  • 结构型设计模式
  • 适配器模式
  • 代理模式
  • 责任链模式
  • 状态模式
  • 桥接模式
  • 组合模式

(三)c++新特性

  • stI容器,智能指针,正则表达式
  • unordered_ _map
  • stl容器
  • hash的用法与原理
  • shared_ ptr,unique_ ptr
  • basic_ regex,sub_ match
  • 函数对象模板function, bind
  • 新特性的线程,协程,原子操作,lamda表达式
  • atomic的用法与原理
  • thread_ local 与condition_ var iable
  • 异常处理exception_ _ptr
  • 错误处理error _ category
  • coroutine的用法与原理

(四)Linux工程管理

  • Makefi le/ cmake/conf igure
  • Makefile的规则与make的工作原理
  • 单文件编译与多文件编译
  • Makefile的参数传递
  • 多目录文件夹递归编译与嵌套执行make
  • Makefile的通配符,伪目标,文件搜索
  • Makefile的操作函数与特殊语法
  • configure生成makefile的原则
  • cmake的写法
  • 分布式版本控制git
  • git的工作流程
  • 创建操作与基本操作
  • 分支管理,查看提交历史
  • git服务器搭建
  • Linux系统运行时参数命令
  • 进程间通信设施状态ipcs
  • Linux系统运行时长upt ime
  • CPU平均负载和磁盘活动iostat
  • 监控,收集和汇报系统活动sar
  • 监控多处理器使用情况mpstat
  • 监控进程的内存使用情况pmap
  • 系统管理员调优和基准测量工具nmon
  • 密切关注Linux系统glances
  • 查看系统调用strace
  • ftp服务器基本信息ftptop
  • 电量消耗和电源管理powertop
  • 监控mysq| 的线程和性能mytop
  • 系统运行参数分析htop/top/atop
  • Linux网络统计监控工具netstat
  • 显示和修改网络接口控制器ethtool
  • 网络数据包分析利刃tcpdump
  • 远程登陆服务的标准协议teInet
  • 获取实时网络统计信息iptraf
  • 显示主机上网络接口带宽使用情况iftop
相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
6月前
|
JSON API 数据库
C++文件服务器项目—数据库表设计 与 后端接口设计—6(三)
C++文件服务器项目—数据库表设计 与 后端接口设计—6(三)
103 0
|
存储 JSON Linux
Linux C/C++开发上线项目(后端、音视频、存储、QT)
Linux C/C++开发上线项目(后端、音视频、存储、QT)
|
存储 应用服务中间件 nginx
奇安信C++后端面经,问的很奇怪!(下)
奇安信C++后端面经,问的很奇怪!
|
算法 Linux 定位技术
C++游戏后端开发,基于魔兽开源后端框架TrinityCore
C++游戏后端开发,基于魔兽开源后端框架TrinityCore
|
Web App开发 存储 Linux
Linux C/C++开发(后端/音视频/游戏/嵌入式/高性能网络/存储/基础架构/安全)(下)
Linux C/C++开发(后端/音视频/游戏/嵌入式/高性能网络/存储/基础架构/安全)
|
存储 Linux 调度
Linux C/C++开发(后端/音视频/游戏/嵌入式/高性能网络/存储/基础架构/安全)(上)
Linux C/C++开发(后端/音视频/游戏/嵌入式/高性能网络/存储/基础架构/安全)
|
存储 应用服务中间件 API
2023秋招C++后端面试项目推荐,5个项目吃透两个offer拿到手软!
2023秋招C++后端面试项目推荐,5个项目吃透两个offer拿到手软!
|
网络协议 算法 Linux
【微信WXG面试】C++后端开发
当需要读两个以上的I/O的时候,如果使用阻塞式的I/O,那么可能长时间的阻塞在一个描述符上面,另外的描述符虽然有数据但是不能读出来,
278 0
【微信WXG面试】C++后端开发
|
算法 NoSQL Java
C++后端开发面试
C++后端开发面试 2019年8月:hello world,就记得opp的多态。 黑马视频《C++ 入门视频》1.5倍数,做笔记和作业,只是最基本的C++常用知识; 《C++Primer 5th》3个月过一遍,这本书相当不错,共分为 19 章:前 8 章为变量、循环等基本知识,第 9-12 章为标准库的知识比如容器算法等,第 13-19 章为设计、拷贝、重载等知识。纸质书上做笔记。 2019年12月买来《Effective C++》、《More Effective C++》、《STL 源码剖析》、《深度探索 C++ 对象模型》; 看完《C++Primer 5th》后就看《STL 源码剖析》,看
265 0
C++后端开发面试
|
4天前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
21 4