【高并发服务器 01】—— 基础知识回顾

接下来四周时间,我将会做一个高并发服务器相关的项目。
前置知识:操作系统系统编程、网络编程、基础的数据结构、C语言。
开发环境:VMware虚拟机:Ubuntu 20.04.6 LTS、vscode
今天先回顾一些基础知识。

1.文件与IO

标准IO(缓冲IO)

  • fread->FILE*
  • fwrite
  • fclose

基础IO

  • open->fd
  • read(recv recvfrom)
  • write
  • close

一切接文件
缓冲池、线程池、连接池

非阻塞IO(nonblock)

  • 如何使用?
    • 如何设置一个非阻塞IO
    • O_NONBLOCK
  • 应用场景?
    • 返回-1:EAGAIN
    • 轮询地去查看IO是否完成
    • 或者使用IO多路复用机制:EPOLL(边缘模式、水平模式)

同步和异步

协议三要素:语法、语义、同步
异步适合于并发。

高级IO

  • select:select count(*) from fds where fd become ready;
  • poll
  • epoll

IO多路复用、IO感知、IO多路转接

selectpollepoll是Linux系统中用于实现IO多路复用的三种机制。它们允许程序同时监控多个文件描述符(file descriptor),以便知道哪个或哪些文件描述符已经准备好进行读写操作。这三种机制的发展体现了从简单到高效的递进关系。

1. select

  • 基本概念:`select`是最早的IO多路复用机制。它允许程序监控多个文件描述符,等待一个或多个文件描述符成为非阻塞状态。
  • 限制:
    • 它支持的文件描述符数量有限,通常受到FD_SETSIZE的限制,默认值通常是1024。
    • 每次调用`select`时,都需要把整个文件描述符集合从用户空间复制到内核空间,这在文件描述符数量较多时会造成较大的性能开销。
    • 每次调用返回时,需要遍历整个文件描述符集合来找出已经准备好的描述符,这也增加了额外的开销。

2. poll

  • 基本概念:`poll`提供了与`select`类似的功能,但解决了`select`的一些限制。
  • 改进:
    • `poll`使用链表而非固定大小的数组,因此不再受FD_SETSIZE的限制,可以监控更多的文件描述符。
    • 与`select`类似,`poll`也需要在每次调用时将整个文件描述符集合从用户空间复制到内核空间,并在返回时检查哪些文件描述符已准备就绪。

3. epoll

  • 基本概念:`epoll`是在Linux 2.6中引入的,它在性能和可扩展性方面对`select`和`poll`进行了显著的改进。
  • 改进:
    • `epoll`可以处理数以万计的并发连接,而不会显著降低性能。
    • 它通过在内核中使用一个事件表来避免每次调用时复制整个文件描述符集合的开销。只有当IO状态真正改变时,应用程序才需要与内核交互。
    • 支持两种模式:LT(水平触发)和ET(边缘触发)。ET模式可以进一步减少系统调用的次数,提高效率。
    • 只有准备就绪的文件描述符会被返回,减少了不必要的遍历。

从`select`到`poll`,再到`epoll`,这三种机制在设计上越来越高效和灵活。`select`和`poll`适合管理少量连接,而`epoll`适合处理大量并发连接,特别是在高性能服务器环境中。随着网络应用对高并发和高性能的需求不断增加,`epoll`成为了Linux下实现高效IO多路复用的首选方案。

2.进程

什么是进程?

程序的映像(image),实例(instance)、运行的程序,动态的、资源分配的基本单位(虚拟内存)、封闭性、独立性

程序、进程、线程、管程、协程的区别?

  • 程序(Program): 是一组指令和数据的集合,是静态的,存储在磁盘上,需要加载到内存中才能执行。
  • 进程(Process): 是程序的一次执行过程,是操作系统进行资源分配和调度的基本单位,具有独立的内存空间和系统资源,进程之间相互独立。
  • 线程(Thread): 是进程中的实际执行单位,一个进程可以包含多个线程,线程共享进程的内存空间和系统资源,但拥有独立的执行路径。
  • 管程(Monitor): 是一种用于并发编程的同步机制,通过提供对共享资源的互斥访问和条件变量的支持来实现线程之间的协作。
  • 协程(Coroutine): 是一种轻量级的线程,可以在不同的执行路径之间切换,但不需要操作系统的支持,由程序员自行控制协程的调度。

fork干了什么事情?

pid判断谁是父亲,谁是孩子、统计信息等不同。
进程三大部分:PCB、数据段、程序段完全拷贝父进程。
写拷贝,如果不做修改,就不拷贝。进程采用段页式管理。拷贝只拷贝一页。
linux采用完全公平算法,放弃了时间片轮转算法。但是仍然具有时间片轮转调度算法的特点。所以往往是父进程先运行。不太可能刚好卡在时间片结束的时候创建子进程。

exec族函数

- p - path (路径): 使用环境变量`PATH`来查找可执行文件。
- v - vector (向量): 参数以字符串数组形式传递。
- l - list (列表): 参数逐个列出。
- e - environment (环境): 允许设置环境变量。

#include <stdio.h>
#include <unistd.h>

int main() {
    // 使用execlp执行ls命令
    execlp("ls", "ls", "-l", NULL);

    // 使用execvp执行ps命令
    char *args[] = {"ps", "aux", NULL};
    execvp("ps", args);

    // 使用execl执行echo命令
    execl("/bin/echo", "echo", "Hello, World!", NULL);

    // 使用execve执行自定义程序
    char *cmd = "./custom_program";
    char *args[] = {"arg1", "arg2", NULL};
    char *env[] = {"PATH=/usr/bin", NULL};
    execve(cmd, args, env);

    // 如果exec函数执行成功,下面的代码将不会被执行
    perror("exec failed");
    return 1;
}

特殊进程

  • 孤儿进程:当一个父进程结束或终止时,它的子进程还在运行,这些还在运行的子进程就会变成孤儿进程。操作系统通常会让init进程(进程号为1的进程)接管这些孤儿进程。接管后,init进程将成为它们的新父进程,负责收集它们的退出状态。

  • 僵尸进程:当一个子进程结束运行,但其父进程尚未通过调用wait()或waitpid()函数来收集子进程的退出状态时,该子进程将成为僵尸进程。僵尸进程已经释放了大部分资源,不再执行任何代码,但在进程表中仍保留一个条目,直到父进程收集其状态信息。

  • 闲逛进程(空闲进程):在操作系统中,闲逛进程(也称为空闲进程或空转进程)是一个特殊的系统进程,当系统中没有其他可运行的进程时,它就会被执行。闲逛进程的主要目的是占用CPU,保证CPU不会处于空闲状态。在多数系统中,闲逛进程的进程号为0。

  • 守护进程:是一种在后台运行的特殊进程,它独立于控制终端,周期性地执行某种任务或等待处理某些发生的事件。守护进程通常在系统引导装入时启动,在系统关闭时终止。与普通的前台进程相比,守护进程的特点是独立于用户和终端,不与任何终端交互。

进程间通信

  • 基于文件的进程间通信
  • 共享内存(shmget、mmap数据的拷贝)
  • pipe(匿名、有名)
  • 条件变量:pthread_cond_signal、pthread_cond_wait(惊群效应)
  • 消息队列
  • socket
  • 信号

3.线程

 什么是线程?

Pthread(Process thread):共享性(共享的是进程空间、竞争、同步 & 互斥:PV操作、信号量)、调度的基本单位,虚拟处理器(让线程感觉自己独占CPU)。

用户线程 & 内核线程

内核能感知到线程吗?内核能感知到内核线程,但是感知不到用户线程。

线程模型

  • 1:1:频繁地对内核线程进行切换。
  • N:1:内核就一个线程,用户N个线程。假设N中的一个阻塞,所有的都会阻塞。
  • M:N:M代表程序的逻辑分支,N代表着程序被调度的机会。 

线程的同步

  • PV
  • 互斥锁
    • 死锁问题
    • 怎么处理死锁(死锁的定义:两个以上资源,资源有限,进程&线程推进不当、死锁避免:银行家算法、死锁预防、死锁检测)

线程的安全

  • 什么是线程的安全?
    • 临界资源:多线程环境下recv能否正确接收
    • 临界区:访问临界资源的那段代码,锁的是临界资源
  • 某个函数线程安全吗?

线程池

  • 池化技术(TCP三次连接的时候很费事,搞个池子一直连着,不需要频繁地创建销毁线程)
  • 怎么实现:构建一个循环任务队列(理发店的等候区)、多个线程(理发店的理发师)、CPU(理发店的工作台)

4.网络编程

socket

应用程序和运输层之间的接口:进程寻址(端口+IP地址)、地址复用

socket编程基础

  • socket
  • bind
  • listen:backlog(backlog参数的意义在于指定了socket可以排队的最大连接数)
  • accept:返回一个新的socketfd
  • connect
  • send & recv(read, write)
  • close

UDP & TCP

  • 区别
  • 三次握手
    • 为什么不是两次,四次可以吗
    • 每次发的都是什么包?
  • 四次挥手
    • 为什么要等2个MSL
    • 为什么四次?
    • 状态转换
  • TCP拥塞控制
  • UDP编程
    • connect
    • recvfrom
    • sendto

网络编程只是系统编程的点缀,本质还是进程间通信。


参数解释及常用的函数方法

socket(AF_INET, SOCK_STREAM, 0) 调用是在 C/C++ 中创建网络套接字的方式之一,主要用于网络通信。这个函数调用涉及到的参数非常关键,下面将对这些参数进行解释:

  1. AF_INET: 这是地址族(Address Family)参数,AF_INET 表示使用 IPv4 网络协议。这是目前最广泛使用的网络类型之一,用于在网络上进行通信。除了 AF_INET,还有 AF_INET6 用于 IPv6 地址,以及其他一些选项用于特定类型的通信(如 AF_UNIX 用于同一台机器上的进程间通信)。

  2. SOCK_STREAM: 这是套接字类型参数。SOCK_STREAM 表示创建的套接字是面向连接的,提供序列化的、可靠的、双向的和基于连接的字节流。这种类型的套接字通常用于 TCP(Transmission Control Protocol)协议。除了 SOCK_STREAM,还有 SOCK_DGRAM 用于无连接的数据报服务(通常与 UDP 协议一起使用),以及其他一些选项。

  3. 0: 这是协议参数。在大多数情况下,给这个参数传递 0 就可以根据地址族和套接字类型自动选择合适的协议。对于 AF_INET 和 SOCK_STREAM 的组合,这通常意味着使用 TCP 协议。如果需要使用特定协议,可以在此处指定,如 IPPROTO_TCP 或 IPPROTO_UDP,但对于 TCP 和 UDP,通常传递 0 就足够了。

htons(prot) 函数用于将主机字节顺序(Host Byte Order)的无符号短整型数值转换为网络字节顺序(Network Byte Order)。这个函数在进行网络编程时非常重要,因为不同的计算机架构可能有不同的字节顺序(即大端序和小端序),而在网络上传输数据时,需要统一使用网络字节顺序,即大端序。

inet_addr("0.0.0.0") 接受一个以点分十进制格式表示的 IP 地址字符串(如 "192.168.1.1")作为参数,并将其转换为用于网络通信的网络字节顺序(大端序)的整数值。

  • "0.0.0.0" 是一个特殊的 IP 地址,用于表示所有可用的主机地址。在服务器端使用此地址作为监听地址时,它意味着服务器将接受连接到该主机上的任何可用网络接口的客户端连接。这对于多网卡的主机尤其有用,因为它允许服务器在所有网络接口上监听,而不需要指定具体的 IP 地址。

setsockopt() 函数用于设置套接字选项,允许程序员控制套接字行为的各个方面。在这个特定的调用中,它被用来设置 SO_REUSEADDR 套接字选项,这对于开发网络应用特别有用。

函数原型

 int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); 
  • sockfd: 套接字文件描述符,指定要操作的套接字。
  • level: 指定选项的代码级别;要访问套接字的选项,则此参数应该设置为 SOL_SOCKET
  • optname: 需要访问的选项名;在这个例子中,它是 SO_REUSEADDR
  • optval: 指向包含新选项值的缓冲区的指针。
  • optlen: 现在选项的值的大小,以字节为单位。

SO_REUSEADDR 选项

  • 目的: 允许重用本地地址和端口。这对于服务器应用尤其重要,因为它允许服务器重启时立即重新绑定到其端口上,即使之前的连接仍处于 TIME_WAIT 状态。没有这个选项,你可能会遇到 "Address already in use" 错误。
  • 参数: 在这个调用中,reuse 是一个整数变量,其值一般设置为非零值(通常是1),以启用 SO_REUSEADDR 选项。

int socket_create(int port) {
	int sockfd;
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		return -1;
	}
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr("0.0.0.0");
	int reuse = 1;
	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(int));
	if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		return -1;
	}
	if (listen(sockfd, 8) < 0) {
		return -1;
	}
	return sockfd;
}

fcntl(fd, F_GETFL)

这行代码是C语言中用于操作文件描述符标志的函数调用。它使用了`fcntl`函数,该函数是一个多功能的文件控制函数,可以对打开的文件描述符进行各种控制操作。`fcntl`函数的原型如下:

int fcntl(int fd, int cmd, ... /* arg */ );

- `fd`:要操作的文件描述符。
- `cmd`:指定要执行的操作类型。
- `...`:根据`cmd`的不同,可能需要提供额外的参数。

在你提供的代码中,`fcntl`函数用于获取文件描述符`fd`的当前状态标志。参数解释如下:

- `fd`:是一个文件描述符,它是一个非负整数,用于标识一个打开的文件。
- `F_GETFL`:是`cmd`参数的一个值,表示获取文件状态标志的操作。

函数调用`fcntl(fd, F_GETFL)`的作用是查询`fd`指向的文件的当前访问模式(如读、写)和文件状态标志(如非阻塞和同步I/O标志)。

函数返回值:

- 成功时,返回文件描述符的访问模式和文件状态标志。
- 失败时,返回-1,并设置`errno`以指示错误原因。

简而言之,这行代码的目的是获取指定文件描述符`fd`的当前文件状态标志。

5.小作业:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/483646.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

软件测试教程 性能测试概论

文章目录 1. 性能测试实施的流程1.1 常见的性能问题1.2 性能测试是什么&#xff1f;1.3 性能测试和功能测试之间的区别1.4 什么样的系统/软件表现属于性能好&#xff0c;什么样的软件性能表现属于性能不好1.5 为什么要进行性能测试1.6 性能测试实施的流程1.7 常见的性能指标以及…

Python虚拟环境conda的安装使用

文章目录 conda虚拟环境的详细步骤和注意事项&#xff1a;**安装Conda****创建Conda虚拟环境****激活Conda虚拟环境****安装Python包****管理Conda环境****其他优势与特性** 相较于venv&#xff0c;使用conda管理虚拟环境有以下优势&#xff1a;**性能****资源占用****其他性能…

【jvm】jinfo使用

jinfo介绍 jinfo 是一个命令行工具&#xff0c;用于查看和修改 Java 虚拟机&#xff08;JVM&#xff09;的配置参数。它通常用于调试和性能调优。 使用 jinfo 命令&#xff0c;你可以查看当前 JVM 的配置参数&#xff0c;包括堆大小、线程数、垃圾回收器类型等。此外&#xf…

立体统计图表绘制方法(分离式环图)

立体统计图表绘制方法&#xff08;分离式环形图&#xff09; 记得我学统计学的时候&#xff0c;那些统计图表大都是平面的框框图&#xff0c;很呆板&#xff0c;就只是表现出统计的意义就好了。在网络科技发展进步的当下&#xff0c;原来一些传统的统计图表都有了进一步的创新。…

unity 多屏幕操作

想了解基础操作请移步&#xff1a;&#xff08;重点是大佬写的好&#xff0c;这里就不再赘述&#xff09; Unity 基础 之 使用 Display 简单的实现 多屏幕显示的效果_unity display-CSDN博客 在panel上也可以通过获取 Canvas&#xff0c;来达到切换多屏幕的操作&#xff0c; …

数据结构基础:一篇文章教你单链表(头插,尾插,查找,头删等的解析和代码)

和我一起学编程呀&#xff0c;大家一起努力&#xff01; 这篇文章耗时比较久&#xff0c;所以大家多多支持啦 链表的结构及结构 概念&#xff1a;链表是⼀种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表 中的指针链接次序实现的。 理解&a…

在MongoDB建模1对N关系的基本方法

“我在 SQL 和规范化数据库方面拥有丰富的经验&#xff0c;但我只是 MongoDB 的初学者。如何建立一对 N 关系模型&#xff1f;” 这是我从参加 MongoDB 分享日活动的用户那里得到的最常见问题之一。 我对这个问题没有简短的答案&#xff0c;因为方法不只有一种&#xff0c;还有…

LangChain核心模块 Retrieval——文档加载器

Retrieval ​ 许多LLM申请需要用户的特定数据&#xff0c;这些数据不属于模型训练集的一部分&#xff0c;实现这一目标的主要方法是RAG(检索增强生成)&#xff0c;在这个过程中&#xff0c;将检索外部数据&#xff0c;然后在执行生成步骤时将其传递给LLM。 ​ LangChain 提供…

探索设计模式的魅力:精准、快速、便捷:游标尺模式在软件设计中的三大优势

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;并且坚持默默的做事。 精准、快速、便捷&#xff1a;游标尺模式在软件设计中的三大优势 文章目录 一、案例场景&…

黑马程序员:C++核心编程——3.函数提高

目录 1.函数默认参数 2.函数占位数 3.函数重载* 1.函数默认参数 形参列表中可以有默认值。 注意&#xff1a;如果某个位置有默认值&#xff0c;那么这个位置之后的都要有。如果函数声明有默认值了&#xff0c;函数实现的时候就不能有默认值&#xff08;防止默认值不同而导…

蓝桥杯第十五届抱佛脚(二)竞赛中的数据结构

蓝桥杯第十五届抱佛脚&#xff08;二&#xff09;内置数据结构 文章目录 蓝桥杯第十五届抱佛脚&#xff08;二&#xff09;内置数据结构在竞赛中常见的数据结构数组(Array)链表(Linked List)栈(Stack)队列(Queue)树(Tree)映射(Map) 内置数据结构的快速使用迭代器&#xff08;It…

综合知识篇20-基于中间件的开发新技术考点(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html案例分析篇00-【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例…

强化学习之父Richard Sutton:通往AGI的另一种可能

2019年&#xff0c;强化学习之父、阿尔伯塔大学教授Richard Sutton发表了后来被AI领域奉为经典的The Bitter lesson&#xff0c;这也是OpenAI研究员的必读文章。 在这篇文章中&#xff0c;Richard指出&#xff0c;过去 70 年来&#xff0c;AI 研究的一大教训是过于重视人类既有…

Python学习从0到1 day18 Python可视化基础综合案例 1.折线图

我默记这段路的酸楚&#xff0c;等来年春暖花开之时再赏心阅读 —— 24.3.24 python基础综合案例 数据可视化 — 折线图可视化 一、折线图案例 1.json数据格式 2.pyecharts模块介绍 3.pyecharts快速入门 4.数据处理 5.创建折线图 1.json数据格式 1.什么是json 2.掌握如何使用js…

用kimichat炒股:查找比亚迪、特斯拉等电动车产业链相关股票

kimichat可以联网检索&#xff0c;搜索结果更加准确、智能。 在kimichat中输入提示词&#xff1a;找出同时在比亚迪产业链和特斯拉产业链的企业 根据您提供的搜索结果中的信息&#xff0c;我们可以找出同时在比亚迪产业链和特斯拉产业链中的企业。以下是从搜索结果中提取的相关…

【动态规划】Leetcode 70. 爬楼梯

【动态规划】Leetcode 70. 爬楼梯 解法1 ---------------&#x1f388;&#x1f388;题目链接&#x1f388;&#x1f388;------------------- 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 输入…

先进电机技术 —— 长线缆驱动电机面临哪些问题?

一、长线驱动问题简述 电机变频驱动器&#xff08;VFD&#xff09;输出侧采用长线缆驱动电机运行时&#xff0c;将会面对多种问题&#xff0c;主要包括但不限于&#xff1a; 此图片来源于网络 1. **电压降**&#xff1a; - 长线缆的电阻会导致电压降增大&#xff0c;当电…

智能优化算法 | Matlab实现牛顿-拉夫逊优化算法Newton-Raphson-based optimize(内含完整源码)

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 智能优化算法 | Matlab实现牛顿-拉夫逊优化算法Newton-Raphson-based optimize(内含完整源码) 源码设计 % ------------------------------------------------------------------------------------------------…

UNI-APP读取本地JSON数据

首先要把json文件放在static文件夹下 然后在要读取数据的页面导入 import data from ../../static/data.json读取数据&#xff1a; onLoad() {console.log(data, data)}, 打印出来的就是JSON文件里的数据了

【SQL】1527. 患某种疾病的患者(like;通配符)

前述 知识点回顾&#xff1a; MySQL 使用OR在LIKE查询中比较多个字段 %&#xff1a;表示任意字符&#xff08;包括0个或多个&#xff09;_&#xff1a;表示任意单个字符匹配空格&#xff1a;直接用空格就行&#xff0c;例如&#xff0c;% DIAB1%可以匹配字符串ACNE DIAB100 …