【高并发服务器 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.小作业:

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uni-app从零开始快速入门

教程介绍 跨端框架uni-app作为新起之秀&#xff0c;在不到两年的时间内&#xff0c;迅速被广大开发者青睐和推崇&#xff0c;得益于它颠覆性的优势“快”&#xff0c;快到可以节省7套代码。本课程由uni-app开发者团队成员亲授&#xff0c;带领大家无障碍快速掌握完整的uni-app…

pandas的综合练习

事先说明&#xff1a; 由于每次都要导入库和处理中文乱码问题&#xff0c;我都是在最前面先写好&#xff0c;后面的代码就不在写了。要是copy到自己本地的话&#xff0c;就要把下面的代码也copy下。 # 准备工作import pandas as pd import numpy as np from matplotlib impor…

linux源配置:ubuntu、centos;lspci与lsmod命令区别

1、ubuntu源配置 1&#xff09;先查电脑版本型号: lsb_release -c2&#xff09;再编辑源更新&#xff0c;源要与上面型号对应 参考&#xff1a;https://midoq.github.io/2022/05/30/Ubuntu20-04%E6%9B%B4%E6%8D%A2%E5%9B%BD%E5%86%85%E9%95%9C%E5%83%8F%E6%BA%90/ /etc/apt/…

【Docker】golang操作容器使用rename动态更新容器的名字

【Docker】golang操作容器使用rename动态更新容器的名字 大家好 我是寸铁&#x1f44a; 总结了一篇golang操作容器使用rename动态更新容器的名字✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 今天遇到一个新的需求&#xff0c;要动态改变运行中的容器名字。 可以考虑先把…

数据结构/C++:哈希表

数据结构/C&#xff1a;哈希表 哈希表概念哈希函数直接定址法除留余数法 哈希冲突闭散列 - 开放定址法基本结构查找插入删除总代码展示 开散列 - 哈希桶基本结构查找插入删除代码展示 哈希表概念 在顺序表中&#xff0c;查找一个数据的时间复杂度为O(N)&#xff1b;在平衡树这…

数据仓库相关概述

数据仓库概述 数据仓库概念 数据仓库是一个为数据分析而设计的企业级数据管理系统。数据仓库可集中、整合多个信息源的大量数据&#xff0c;借助数据仓库的分析能力&#xff0c;企业可从数据中获得宝贵的信息进而改进决策。同时&#xff0c;随着时间的推移&#xff0c;数据仓…

3个Tips,用“AI”开启新生活

相信最近&#xff0c;很多朋友们都回归到了忙碌的生活节奏中。生活模式的切换&#xff0c;或多或少会带来身体或情绪状况的起伏。新技术正在为人们生活的方方面面带来便利。3个小Tips或许能让你也从新技术中获益&#xff0c;从身到心&#xff0c;用“AI”开启新生活。 关”A…

【Linux杂货铺】进程控制

目录 &#x1f308;前言&#x1f308; &#x1f4c1; 进程创建 &#x1f4c2; fork函数 &#x1f4c2; 写实拷贝 &#x1f4c2; 创建进程的目的 &#x1f4c2; 创建失败原因 &#x1f4c1; 进程终止 &#x1f4c2; 概念 &#x1f4c2; 场景 &#x1f4c2; 退出方法 …

使用React搭建single-spa

自己搭建的Demo GitHub - ftao123/single-spa-react-demo: single-spa-react-demo 修改子应用的webpack配置 library: "app2"和libraryTarget: "umd"配置必须添加。 可以看到filename在开发环境下的地址是static/js/bundle.js&#xff0c;所以我们主应用…

【Delphi JCL库文件解剖 1】库文件的大体脉络

JCL库是一个开源的Delphi库文件,下载到它很容易,可是想能灵活运用它却并不容易。下面是这个库文件的大体文件脉络,咱们要分析的核心还是在 source 源代码文件。 bin - 示例应用程序可执行文件的常见位置 docs - 读…

JavaEE-文件操作和IO

我们先来认识狭义上的⽂件(file)。针对硬盘这种持久化存储的I/O设备&#xff0c;当我们想要进⾏数据保存时&#xff0c;往往不是保存成⼀个整体&#xff0c;⽽是独⽴成⼀个个的单位进⾏保存&#xff0c;这个独⽴的单位就被抽象成⽂件的概念&#xff0c;就类似办公桌上的⼀份份真…

Java程序设计 4、5章 练习题

一、填空题 1.假设有 String s1 "Welcome to Java"; String s2 s1; String s3 new String("Welcome to Java"); 那么下面表达式的结果是什么&#xff1f; (1) s1 s2 ___________true_______________ (2) s1 s3 ______…

C++ Thread 源码 观后 自我感悟 整理

Thread的主要数据成员为_Thr 里面存储的是线程句柄和线程ID 先看看赋值运算符的移动构造 最开始判断线程的ID是否不为0 _STD就是使用std的域 如果线程ID不为0&#xff0c;那么就抛出异常 这里_New_val使用了完美转发&#xff0c;交换_Val和_New_val的值 _Thr _STD exchange(_…

【动手学深度学习】深入浅出深度学习之PyTorch基础

目录 一、实验目的 二、实验准备 三、实验内容 1. 数据操作 2. 数据预处理 3. 线性代数 4. 微积分 5. 自动微分 四、实验心得 一、实验目的 &#xff08;1&#xff09;正确理解深度学习所需的数学知识&#xff1b; &#xff08;2&#xff09;学习一些关于数据的实用…

如何设置Word文档的高级属性?这里有详细步骤

我们最近向你展示了如何在Word中设置用户信息。Word还存储与文档相关的几个其他高级属性。其中一些显示在“信息”屏幕上&#xff0c;你可以更改这些属性。 注意&#xff1a;我们使用Word 2013来说明此功能。 要访问允许你更改当前打开文档的属性的对话框&#xff0c;请单击“…

使用 Amazon SageMaker 微调 Llama 2 模型

本篇文章主要介绍如何使用 Amazon SageMaker 进行 Llama 2 模型微调的示例。 这个示例主要包括: Llama 2 总体介绍Llama 2 微调介绍Llama 2 环境设置Llama 2 微调训练 前言 随着生成式 AI 的热度逐渐升高&#xff0c;国内外各种基座大语言竞相出炉&#xff0c;在其基础上衍生出…

☆【前后缀】【双指针】Leetcode 42. 接雨水

【前后缀】【双指针】Leetcode 42. 接雨水 解法1 前后缀分解解法2 双指针 ---------------&#x1f388;&#x1f388;42. 接雨水 题目链接&#x1f388;&#x1f388;------------------- 解法1 前后缀分解 维护一个前缀&#xff08;左侧最高&#xff09;后缀&#xff08;右侧…

ASP .Net Core ILogger日志服务

&#x1f433;简介 ILogger日志服务是.NET平台中的一个内置服务&#xff0c;主要用于应用程序的日志记录。它提供了灵活的日志记录机制&#xff0c;允许开发者在应用程序中轻松地添加日志功能。以下是其主要特点和组件&#xff1a; ILogger接口&#xff1a;这是ILogger日志服…

147 Linux 网络编程3 ,高并发服务器 --多路I/O转接服务器 - select

从前面的知识学习了如何通过socket &#xff0c;多进程&#xff0c;多线程创建一个高并发服务器&#xff0c;但是在实际工作中&#xff0c;我们并不会用到前面的方法 去弄一个高并发服务器&#xff0c;有更加好用的方法&#xff0c;就是多路I/O转接器 零 多路I/O转接服务器 多…

数据库系统概论(超详解!!!) 第四节 关系数据库标准语言SQL(Ⅰ)

1.SQL概述 SQL&#xff08;Structured Query Language&#xff09;结构化查询语言&#xff0c;是关系数据库的标准语言 SQL是一个通用的、功能极强的关系数据库语言 SQL的动词 基本概念 基本表 &#xff1a;本身独立存在的表&#xff1b; SQL中一个关系就对应一个基本表&am…