阻塞/非阻塞、同步/异步
    典型的一次IO的两个阶段是 等待读写就绪、就绪后的数据读写。
    等待读写就绪:根据系统IO操作分为阻塞和非阻塞(函数是直接返回就绪状态还是在就绪后才返回 阻塞的话挂起是不占用CPU资源的)
    数据读写:根据应用程序和内核的交互方式分为同步和异步(通过API从内核读缓冲区读或向内核写缓冲区写 以读为例API需要将内核读缓冲区内的数据全部搬到用户态下定义的一块空间 这个搬运过程是在用户态下进行的也是比较耗时的 在搬运完成前API是不会返回的(同步)。 异步则是应用程序给定一块空间给内核内核OS来帮助我们完成搬运!! API直接返回,应用程序执行其他内容不需要等待搬运完成 在搬运完成后通过我们指定的通知方式(信号)来告诉我们搬运完成 我们给定的空间中已经装好读缓冲区的数据)
    陈硕:在处理IO的时候,阻塞和非阻塞都是同步IO 只有使用了异步专用的API才是使用异步IO
    图片1.png图片2.png

    几种常见的IO模型

    同步IO
    1阻塞等待 阻塞IO模型(Blocking IO)
    使用系统调用并一直阻塞到内核将数据准备好,之后再将数据从内核缓冲区复制到用户区中,在内核将数据准备好之前什么也干不了
    下图函数调用期间一直被阻塞直到数据准备好且从内核复制到用户程序时系统调用才解除阻塞函数返回
    图片1.png
    阻塞期间用户线程挂起不会占用CPU资源。但只能一个线程维护一个IO,如果要用于并发需要开启大量线程用来维护网络连接(我们之前写的就是这种) 就是Linux中阻塞的read

    2 非阻塞IO (Non-blocking IO)
    内核在没准备好数据的时候会直接返回错误码,不会阻塞。调用程序不会挂起,而是不断轮询内核数据是否准备好。非阻塞式IO的轮询会耗费大量cpu,通过将调节字描述符属性设置为非阻塞可使用该功能。 Linux中非阻塞read
    如果服务器连接了成千上万个客户端,每一次调用recv都需要去遍历这成千上万的fd看是否有数据到达,非常低效
    每次发起IO调用,在内核等待数据的过程中可以立即返回,用户线程不会阻塞,实时性较好。 但是在并发时多个线程不断轮询内核是否有数据,会占用大量CPU时间,效率不高。一般web服务器不采用此模式。
    图片2.png
    对于非阻塞(accept,recv,send)事件没有发生就返回-1,出错也是返回-1,可以通过errno来判断是否发生错误,errno为EGAIN或EWOULDBLOCK则是事件没有发生继续即可

    3多路复用IO(IO Multiplexing)

    类似于非阻塞,但是轮询不由用户线程执行而是由内核线程去轮询,内核监听程序听到数据准备好后,调用内核函数复制数据到用户态。
    比如下图中的select 这个系统调用充当代理的角色,不断轮询select注册的所有需要IO的文件描述符,当多个套接字的任意一个的数据准备好了,用户线程再调用read将数据从内核区复制到用户区(复制的过程中 进程阻塞)。
    图片3.png

    select 线性扫描所有监听的为念描述符,不管它们是否活跃(监听数量有上限 32位机1024 64位机 2048)
    poll 同select但是数据结构不同,需要分配一个pollfd数据结构数组在内核中,没有大小限制(无监听上限) 不过需要很多复制操作
    slect和poll。只会告诉你有几个fd接收到消息了,但是不会告诉你是哪几个fd还是需要后续自己去遍历

    epoll 无大小限制(无监听上限)。使用一个文件描述符管理多个文件描述符,使用红黑树存储。同时用事件驱动代替轮询。epoll_ctl中注册的文件描述符在事件触发的时候会通过回调机制激活该文件描述符,epoll_wait函数返回。并且采用mmap虚拟内存映射技术减少用户态和内核态数据传输的开销。
    epoll会告诉你有几个fd接收到消息了,也会告诉你是哪几个fd消息到了

    系统不必维护大量线程只需要一个线程就能处理大量的连接监听。本质上select/epoll系统调用是阻塞式的,属于同步IO,需要在读写事件就绪后,再有系统读写系统调用进行阻塞的读写。

    4 信号驱动式IO
    当内核数据准备就绪时通过信号来通知,当数据准备好内核会发送SIGIO信号,收到信号后再进行io操作。第一阶段无需等待数据是否准备好(异步),但还是需要用户自己从内核拷贝内容到用户态(同步)
    图片4.png
    5异步IO(Asynchronous IO)
    异步IO依赖信号处理函数进行通知,和前面的同步IO模型的不同点在于 前面的都是数据准备阶段的阻塞与非阻塞,但是异步IO直接通知IO操作是否完成
    异步IO才是真正的非阻塞,主进程只负责做自己的事,等IO操作完成(内核将数据成功从内核中复制到应用程序空间)时通过回调函数对数据进行处理
    unix总异步io函数以aio或lio打头
    图片5.png
    真正实现了非阻塞,吞吐量在几种模式中是最高的,
    需要内核支持,异步IO在Linux2.6才引入,目前并不完善,其底层实现仍使用epoll
    图片1.png
    5种IO模型对比
    图片2.png
    web server(网页服务器)
    听过一http协议与客户端(浏览器)进行通信,接收存储处理来自客户端的HTTP请求,并对其请求做出http响应,返回给客户端请求的内容。
    用户在使用浏览器与相应服务器进行通信,在浏览器中键入”域名”—”IP地址:端口号”,如果输入的是域名浏览器则先将输入的域名解析成相应的IP地址和端口号,再通过TCP三次握手建立与目标Web服务器的连接,然后http协议生成针对目标web服务器的http请求报文,通过tcp ip协议封装http报文再发到web服务器上。

    http协议(应用层的协议)
    超文本传输协议是一个简单的请求-响应协议,它规定了客户端可能发给服务器什么样的消息已经得到什么样的响应。请求和响应消息的头以ASCII形式给出,详细内容具有一个类似MIME的格式。
    客户端发起一个HTTP请求到服务器上指定端口(默认端口为80)
    www.baidu.com 就相当于ip地址了 也叫url
    www.baidu.com:80 http
    www.baidu.com:443 https
    ,我们称这个客户端为用户代理程序(user agent),应答的服务器上存储着一些资源,比如HTML文件和图像。我们称这个应答服务器为源服务器(origin server)。在代理程序和源服务器中间可能存在多个”中间层”比如代理服务器、网关或者隧道。
    http协议假定其下层协议提供可靠的传输,因此任何能够提供这种保证的协议都可以被其使用,一般选择TCP作为传输层

    工作原理
    http协议规定了浏览器如何从web服务器请求web页面,以及服务器如何把web页面传送给客户端。http协议采用了请求/响应模型,客户端向服务器发送一个请求报文,请求报文包含请求的方法、URL、协议版本、请求头部和请求数据。服务器以一个状态行 作为响应,响应的内容包括协议的版本、成功或者错误代码、服务器信息、响应头部和响应数据。
    http请求/响应的步骤:
    1 客户端连接到web服务器
    浏览器与web服务器的http端口(默认为80)建立一个tcp套接字连接(3次握手)
    2 发送http请求
    通过tcp套接字,浏览器向web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据4部分组成
    3 服务器接收请求并返回http响应
    web服务器解析请求,定位请求资源。服务器将资源副本写到tcp套接字,由浏览器读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。
    4 释放TCP连接
    若connection模式为close,则服务器主动关闭tcp连接,浏览器被动关闭连接释放tcp连接,若connection模式为keep alive则该连接会保持一段事件在该事件内可以继续接收请求。
    5 浏览器解析HTML内容
    浏览器首先解析状态行,查看状态行中表示请求是否成功的状态代码。然后解析问一个响应头,响应头告知若干字节的HTML文档和文档的字符集。浏览器读取响应数据HTML,根据HTML语法对其进行格式
    化,并在浏览器窗口中显示。
    在浏览器地址栏键入URL并按下回车
    1 浏览器向DNS服务器请求解析该URL中的域名所对应的IP地址
    2 解析出IP地址后 根据该IP地址和默认端口80 与服务器建立TCP连接
    3 浏览器发出读取文件(URL域名后面的一部分包含要读取的对应文件)的HTTP请求,该请求报文作为TCP三次握手的第三个报文的数据发送给服务器
    4 服务器对浏览器请求做出相应 并把对应的HTML文本发送给浏览器
    5 释放TCP连接
    6 浏览器将该HTML文本内容显示
    肯定是从浏览器(客户端)开始建立通信的,服务器端在没有接收到请求之前不会发送响应(一个请求对应一个响应)
    浏览器F12 NETWORK中会记录HTTP的报文 请求响应都会记录

    图片3.png
    http请求报文
    GET / HTTP/1.1 请求行:请求方法GET空格URL/空格协议版本HTTP/1.1回车换行
    下面都是请求头部 字段名:值 回车换行
    Host: www.baidu.com 字段名HOST:值wwww.baidu.com
    Connection: keep-alive
    Cache-Control: max-age=0
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36 Sec-Fetch-User: ?1
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3 有多个值使用逗号隔开
    Sec-Fetch-Site: none
    Sec-Fetch-Mode: navigate
    Accept-Encoding: gzip, deflate, br
    Accept-Language: zh-CN,zh;q=0.9
    Cookie: BIDUPSID=ED090A58CC359E927A53C0D9672C8CE2; PSTM=1550631365; BD_UPN=12314753; BDUSS=5OLWJ5UDJnaklsS1ZvNFJ4WlZ2MkU1YTBTNkpsWUxOb0xCeXFXYWJVQnVHLU5mRVFBQUFBJCQAAAAAAAAAAAEAAAAtDk6iSkxlcjY2NgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG6Ou19ujrtfbX; BDUSS_BFESS=5OLWJ5UDJnaklsS1ZvNFJ4WlZ2MkU1YTBTNkpsWUxOb0xCeXFXYWJVQnVHLU5mRVFBQUFBJCQAAAAAAAAAAAEAAAAtDk6iSkxlcjY2NgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG6Ou19ujrtfbX; __yjs_duid=1_c841cfe68aa79024b49038ca82d3cee31619871170993; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BDSFRCVID_BFESS=PyKOJeC6276Y7IjH3A35bV0MIfRYIA6TH6f3-b1yi2LZhjT27GGTEG0PEx8g0Kub4uaaogKKKgOTHICF_2uxOjjg8UtVJeC6EG0Ptf8g0f5; H_BDCLCKID_SF_BFESS=tbAt_CDyJDP3jt-kM-5b5JF_hmT22-usLT5i2hcH0KLKMIQXjUr8y5tFDNoaLjOuWCcNhlTpJfb1MRLRqtKa2tcXXb63aq0HJ2vx-p5TtUJpJKnTDMRh-600-fQyKMniWKv9-pnY0hQrh459XP68bTkA5bjZKxtq3mkjbPbDfn02eCKu-n5jHj3BjND83j; BAIDUID=D0D86788357519120608F7DC384CD6FC:FG=1; delPer=0; BD_CK_SAM=1; H_PS_PSSID=34299_34319_34369_31660_34377_34004_34073_34092_34107_34094_26350_34237_34366; PSINO=5; COOKIE_SESSION=25428_7_3_3_20_3_0_0_3_2_202_1_25606_25610_205_185_1628595102_1628595082_1628594897%7C9%2325428_20_1628594897%7C9; BD_HOME=1; sugstore=0; BA_HECTOR=al01ah2g0ka52h2h6l1gh52ki0r
    cookie中包含了大量内容 看不懂
    回车换行

    响应报文头
    HTTP/1.1 200 OK 协议版本HTTP/1.1空格状态码200空格状态描述码OK回车换行
    Bdpagetype: 2
    Bdqid: 0xa69df409000504f0
    Cache-Control: private
    Connection: keep-alive
    Content-Encoding: gzip
    Content-Type: text/html;charset=utf-8
    Date: Tue, 10 Aug 2021 14:18:12 GMT
    Expires: Tue, 10 Aug 2021 14:18:12 GMT
    Server: BWS/1.1
    Set-Cookie: BDSVRTM=325; path=/
    Set-Cookie: BD_HOME=1; path=/
    Set-Cookie: H_PS_PSSID=34299_34319_34369_31660_34377_34004_34073_34092_34107_34094_26350_34237_34366; path=/; domain=.baidu.com
    Strict-Transport-Security: max-age=172800
    Traceid: 1628605092061326541812006020501131822320
    X-Frame-Options: sameorigin
    X-Ua-Compatible: IE=Edge,chrome=1
    Transfer-Encoding: chunked
    回车换行
    响应正文
    <!DOCTYPE html>


    …..

    http请求方法
    http/1.1中定义了八种方法(也叫动作)来以不同方式操作指定的资源
    1 GET:向指定的资源发出显示请求,我们再使用GET方法时GET方法应该只用在读取数据而不应当用于产生 副作用的操作中
    2 HEAD:与GET方法一样,都是向服务器发出指定资源的请求,只不过服务器将不传回资源的本文部分。它的好处在于,使用这个方法可以在不必传输全部内容的情况下,就可以获取其中 关于该资源的信息(元信息)
    3 POST:向指定资源提交数据,请求服务器进行处理。比如上传文件,上传登录用的账户和密码。数据被包含在请求本文中,这个请求可能会创建新的资源或修改现有资源
    4 PUT:向指定资源位置上传其最新内容
    5 DELETE:请求服务器删除Request-URI所标识的资源
    6 TRACE:回显服务器收到的请求,主要用于测试或诊断
    7 OPTIONS:这个方法可使服务器传回该资源所支持的所有HTTP请求方法,用*来代替资源名称,向WEB服务器发送OPTIONS请求可以测试服务器功能是否正常运作
    8 CONNECT:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器,通常用于SSL加密服务器的链接(经由非加密的HTTP代理服务器)

    http状态码
    所有HTTP响应的第一行都是状态行,依次是当前HTTP版本号,3位数字组成的状态代码,以及描述状态的短语彼此用空格分开
    状态码的第一个数字代表当前响应类型
    1xx消息—请求已被服务器接收 继续处理
    2xx成功—请求已被服务器接收 理解 并接受 200 OK
    3xx 重定向—需要后续操作才能完成这一请求
    4xx请求错误—请求含有词法错误或者无法被执行 404 NOT FOUND
    5xx 服务器错误—服务器在处理某个正确请求时发送错误
    web开发者能够自行决定采用哪种数字 用以显示本地化的状态描述或自定义信息
    图片1.png
    服务器编程基本框架和两种高效的事件处理模式

    服务器程序种类繁多,但其基本框架基本一样不同之处在于逻辑处理
    图片1.png
    IO处理单元 处理客户端连接,读写网络数据
    等待并接受新的客户连接,接收客户数据,将服务器响应数据返回给客户端。但是数据的收发不一定在IO单元中执行,也可能在逻辑单元中执行,具体在何处执行取决于事件处理模式。
    逻辑单元 业务进程或线程
    进程或线程分析处理客户数据,然后将结果传递给IO处理单元或直接发给客户端 具体行为取绝于事件处理模式。服务器通常拥有多个逻辑单元,以实现对多个客户任务的并发处理。
    网络存储单元 数据库、文件或缓存
    请求队列 各单元之间的通信方式(进程/线程间通信)
    IO处理单元收到客户请求时,需要以某种方式通知一个逻辑单元来处理该请求,同样多个逻辑单元同时访问一个存储单元时也需要采用某种机制来协调处理竞态条件,请求队列通常被认为时池的一部分
    已有的开源的web服务器框架 tomcat nigx

    两种高效的事件处理模式
    Reactor(同步IO模型)和Proactor(异步IO模型 也不一定同步IO也可以用这种模式)

    Reactor模式
    要求主线程(IO处理单元)只负责监听文件描述符是否发生对应事件,有的话立即将该事件通知工作线程(逻辑单元),将socket可读可写事件放入请求队列,交给工作线程处理。除此以外主线程不做任何实质性工作。读写数据,接受新的连接,以及处理客户请求均在工作线程中完成。
    使用IO实现的Reactor模式的工作流程:
    1 主线程往epoll内核事件表中注册socket上的读就绪事件
    2 主线程调用epoll_wait等待socket上有数据可读
    3 当socket上有数据可读时,epoll_wait通知主线程,主线程则将socket可读事件放入请求队列
    4 唤醒某个在请求队列中的工作线程(之前在睡眠),它从socket读取数据 并处理客户请求,然后往epoll内核事件表中注册该socket上的写就绪事件
    5 主线程调用epoll_wait等待socket可写
    6 当socket可写时,epoll_wait通知主线程。主线程将可写事件放入请求队列
    7 唤醒某个在请求队列中的工作线程(之前在睡眠),它往socket上写入服务器处理客户请求的结果
    图片1.png
    Proactor模式
    Proactor模式将所有I/O操作都交给主线程和内核来处理(读写),工作线程仅负责业务逻辑。使用异步IO模型(aio_read aio_write)实现Proactor模式的工作流程如下
    1 主线程调用aio_read函数向内核注册socket上的读事件,并告诉内核 这个socket的读缓冲区的位置,以及读操作完成时如何通知应用程序(信号)
    2 主线程继续处理其他逻辑
    3 当读缓冲区数据就绪,并且内核也已经将数据拷贝到用户态了,内核向应用程序发一个信号,通知应用程序数据已经可用(读IO由主线程和内核处理完后 再通知工作线程处理业务)
    4 应用程序预先定义好的信号处理函数选择一个工作线程来处理客户请求。工作线程处理完客户请求后,调用aio_write函数向内核注册socket上的写事件,并告诉内核 这个socket的写缓冲区的位置,以及读操作完成时如何通知应用程序(信号)
    5 主线程继续处理其他逻辑
    6 当写缓冲区有空余空间,并且内核也已经将数据拷贝到内核态了,内核向应用程序发一个信号,通知应用程序数据已经发送完毕(写IO由主线程和内核处理完后 再通知工作线程处理业务)
    7 应用程序预先定义好的信号处理函数选择一个工作线程来作善后处理 比如决定是否关闭socket
    图片1.png

    使用同步IO模拟Proactor模式
    主线程执行IO读写,读写完后 主线程向工作线程通知读写完成。从工作线程的角度来看 他们直接获得了数据读写的结果,接下来就是对读写的结果进行逻辑的处理
    1 主线程往epoll内核事件表中注册socket读事件
    2 主线程调用epoll_wait 等待socket上有数据可读
    3 当socket上有数据可读时,epoll_wait通知主线程,主线程从socket循环读数据,直到没有更多数据可读,然后读取到的数据封装成一个请求对象并插入请求队列
    4 睡眠再请求队列上的某个工作线程被唤醒,它获得请求对象并处理客户请求,然后往epoll内核事件表汇总注册socket上的写事件
    4 主线程调用epoll_wait等待socket可写
    5 当socket可写时,epoll_wait通知主线程 主线程往socket上写入服务器处理客户请求的结果
    图片1.png
    线程同步机制类封装以及线程池实现

    线程池
    线程池是由服务器预先创建的一组子线程,线程池中的线程数量应该和CPU数量差不多。线程池中的所有子线程都运行相同的代码。当新任务到来时,主线程将通过某种方式选择线程池中的某一个子线程来为之服务。相比于动态地创建子线程,选择一个已经存在的子线程的代价显然要小得多。 主线程选择哪个子线程来执行新任务有多种方式(类似于cpu调度)
    (在线程池中创建固定数量的线程 而不是像之前一样每有一个客户端连接就为其创建一个线程专门为它工作)

    最简单地主线程使用随机算法和轮流选取,有很多更好的算法可使任务在各个线程中分配地更均匀。 还有一种方法就是主线程和所有子线程通过一个共享的工作队列来同步,子线程都睡眠在共享队列上。当有新任务到来时,主线程将任务添加到工作队列中,这将唤醒正在等待任务的子线程(只有一个子线程将获得新任务的接管权)
    图片1.png
    线程池中的线程数量的最直接的限制因素时CPU的处理器数量,假设为4核。对于CPU密集型的任务(如视频剪辑等消耗CPU算力的任务来说) 线程池中的线程数量最好设置为核数的1-2倍(或+1防止其他因素造成的线程阻塞)。对于IO密集型的任务,要多余CPU核数,因为线程间竞争的不是CPU资源而是IO资源,IO的处理一般很慢,多余核数的线程将为CPU争取更多的任务,不至于在线程处理IO的过程造成CPU空闲导致资源浪费。
    线程数 = CPU核数*(1+IO耗时/CPU耗时)
    线程的 CPU 耗时所占比例越高,就需要越少的线程
    线程的 IO 耗时所占比例越高,就需要越多的线程
    针对不同的程序,进行对应的实际测试就可以得到最合适的选择
    线程数 >= CPU 核心数
    线程池内线程数量应该动态改变更好

    池是一组资源的集合,这组资源在服务器启动之初就被完全创建好并初始化,这被称为静态资源。当服务器进入正式运行阶段,开始处理客户请求的时候,如果它需要相关的资源可以直接从池中获取,无需动态分配。当服务器处理完一个客户连接后可以直接把资源方回池中(改一个标致)无需执行系统调用释放资源。

    EPOLLONESHOT事件
    即使使用epoll中的ET模式(边沿触发模式),一个socket上的某个事件(读就绪、写就绪)还是可能被触发多次。这在并发程序中就会引起一个问题,比如一个线程在读完某个socket上的数据后开始处理这些数据,而在数据处理的过程中该socket上又有新数据可读(EPOLLIN再次被触发),此时另外一个线程将被唤醒去处理这个新数据(实际为早先的同一数据),于是就出现了两个线程同时操作一个socket的局面。一个socket连接在任一时刻都只被一个线程处理,可以使用EPOLLONESHOT实现。
    对于注册了EPOLLONESHOT事件的文件描述符,OS上最多触发其上注册的一个可读、可写或者异常事件,且只触发一次(所以在oneshot处理完后我们需要重新注册一次这个socket到epoll内核)。这样当一个线程在处理某个socket时其他线程是不可能有机会操作该socket的。但注意,注册了EPOLLONESHOT的socket一旦被某个线程处理完,该线程应该立即用epoll_ctl重置这个socket上的EPOLLONESHOT事件,以确保这个socket在下一次可读时,其EPOLLIN事件能被触发,从而让其他工作线程有机会处理这个socket。

    有限状态机
    逻辑单元内部的一种高效编程方法:有限状态机
    有的应用层协议头部包含数据类型,每种类型可以映射为逻辑单元的一种执行状态,服务器可以根据他来编写相应的处理逻辑
    图片1.png
    该状态机包含三种状态type_A,type_B,type_C。其中type_A是状态机的开始状态,type_C是状态机的结束状态。状态机的当前状态记录在cur_state中。在经过一次循环后,状态机先通过getNewPackage方法获得一个新的数据包,然后根据cur_state的变量值来判断如何处理该数据包,数据包处理完后根据状态转移将cur_state设定为下一状态 继续循环

    服务器压力测试
    webbench是常用的一种web性能压力测试工具,测试在相同硬件上,不同服务的性能以及不同硬件上同一个服务的运行状况。展示服务器的两项内容:每秒钟响应请求数和每秒钟传输数据量。
    原理: webbench会fork出多个子进程 每个子进程都循环做web访问测试,子进程把访问结果通过pipe告诉父进程,父进程做最终的统计

    webbench -c 1000 -t 30 http://IP:pirt/资源页
    参数
    -c表示forck出的子进程数量(客户端数量)
    -t 表示时间,每个客户端的访问时间

    rm 被删除的文件 rm *.o表示删除当前目录下的所有.o后缀文件
    cd ..移动到上一级目录
    cp -r calc/ library ../lesson05将当前目录下的calc/ library文件夹复制到的上级目录(../)下的lesson05文件夹内 -r表式递归拷贝
    mv 目标文件 目标路径
    pwd 能输出当前所在的绝对路径
    ll -h 文件名 文件名 。。。 查看指定文件名的读写权限 创建时间大小…
    ctrl+l清屏
    vim中set nu 可以显示行号
    ln -s a.txt b.txt 将b.txt软连接到a.txt上 b.txt->a.txt 之后再打开b.txt实际上是打开a.txt
    man 1 linux系统命令 可以查看这个命令的说明

    进程快照并非实时
    ps aux a:显示终端上的所有进程 包括其他用户的进程(可有多用户登录同一服务器) u:显示进程的详细信息 x:显示没有控制终端的进程
    tty 命令查看当前界面属于哪个终端
    ps ajx j:列出与作业控制相关的信息 会列出进程组 会话 id

    kill -SIGKILL pid 根据上面的序号表我们知道 SIGKILL就是9
    kill -9 pid 加 -9 表示的是 9 号信号。其实kill并不是杀死进程,而是发送信号,而 9 号信号能够强制杀死进程,其它的信号有的可以有的不可以
    killall name 根据进程名杀死进程

    实时显示进程动态状态
    top 可以 top -d 刷新时间 来指定信息更新的时间间隔(单位为秒) 在top执行后 可以按以下按键来对显示结果排序(都是降序排序)
    M 根据内存使用量排序
    P 根据CPU占有率排序
    T 根据进程运行时间长短来排序
    U 根据用户名来筛选进程 (按u后会让你输入进程名)
    K 输入指定的PID来杀死那个对应进程(按k后会让你输入 PID号)

    再插一句在执行可执行文件时可以在后面加个&号 表示在后台执行 不会占用我们当前的终端,当前终端还可以执行其他命令 并且返回这个可执行文件启动的进程的进程号。但是printf的信息依旧会在当前窗口打印 但是不影响。 ./a.out & 进程在后台执行 在命令行输入fg回车可将进程变回到前台终端执行

    ctrl+z 将当前命令行执行的进程切换到后台执行 即当前命令行不会输出这个进程的相关信息 这个进程也不会再占用这个前台终端 终端可以执行其他命令 但是这个进程依旧在跑