- 博客(79)
- 资源 (2)
- 收藏
- 关注
原创 C/C++中各个位置的const关键字
Ⅰconst修饰函数常函数 --- 成员函数名后加const函数前加constⅡ 修饰引用Ⅲ 修饰指针常内容指针(不允许解指针)常指针常内容常指针
2023-01-07 11:46:02 874 1
原创 mmap(内存映射)、sendfile() 与零拷贝技术
对于一个IO操作而言,都是通过CPU发出对应的指令来完成的,但是相比于CPU来说,IO的速度太慢了,CPU有大量时间处于等待IO的状态,因此就产生了DMA直接内存访问技术,本质上来说DMA就是一块主板上独立的芯片,通过它来进行内存和IO设备的数据传输,从而减少了CPU的等待时间,但是不论是谁来拷贝,频繁的拷贝耗时也是对性能的影响。一次简单的传统IO过程,发生了4次用户态和内核态的上下文切换,这在高并发场景下无疑会对性能产生极大的影响。
2023-01-07 11:42:11 2014
原创 共享内存原理与使用
不同进程之间共享的内存通常为同一段物理内存。就好比,我要和人solo(通信),我创建了一个房间(共享内存),这个房间就有了房间号(共享内存的ID),是个人都能进这个房间,根本没法通信,所以我们要设置房间密码。第一,和创建进程类似,进程被创建的时候,会被分配一个pid来标识这个进程的唯一性,同时也方便OS管理这些进程,因此共享内存在被创建的时候,会被分配一个“ID”来标识唯一性。第二,共享内存可以允许存在多个,为了区分这些共享内存,我们上面引入了“ID”的概念,但是要如何让两个进程连上同一个共享内存呢?
2023-01-07 11:33:47 1586
原创 进程间的8种通信方式
无名管道( pipe )、高级管道(popen)、有名管道(named pipe)、消息队列( message queue )、信号量( semophore ) 、信号 ( sinal ) 、共享内存( shared memory ) 、套接字( socket )。进程的亲缘关系通常是指父子进程关系。将另一个程序当做一个新的进程在当前程序进程中启动,则它算是当前程序的子进程,这种方式我们成为高级管道方式。套解字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。
2023-01-07 11:26:59 2114
原创 虚拟地址空间相关知识网络(段页存储 -- MMU -- 虚拟地址 -- 内核区 -- 用户区)
段页式存储 ----> 逻辑地址到物理地址映射(MMU) ----> 进程地址空间(用户地址空间和PCB)-----> 缺页中断和缺页请求
2023-01-07 11:24:25 1453
原创 select、poll、epoll的简要对比
select的几大缺点:(1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大(2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大(3)select支持的文件描述符数量太小了,默认是1024select 为什么是1024?—— 两个10241,select中存放文件描述符的数组大小FD_SETSIZE为10242,进程的文件描述符上限默认是1024,正是因为这个原因,select设计时才把数组大小设计为1024。
2023-01-07 11:14:11 856
原创 C++内联函数(inline)和宏函数(define)对比
1.C中使用define这种形式宏定义的原因是因为C语言是一个效率很高的语言,这种宏定义在形式及使用上像一个函数,但它使用预处理器实现,没有了参数压栈,代码生成等一系列的操作。因此,效率很高,这是它在C中被使用的一个主要原因。2.这种宏定义在形式上类似于一个函数,但在使用它时,仅仅只是做预处理器符号表中的简单替换,因此它不能进行参数有效性的检测,也就不能享受C++编译器严格类型检查的好处,另外它的返回值也不能被强制转换为可转换的合适的类型。这样,它的使用就存在着一系列的隐患和局限性。3.在C++中引
2023-01-07 11:09:14 984
原创 static关键字分别在C和C++中的作用
一般在函数中定义的变量,在栈区分配空间,函数退出时胡自动释放,无法保存,而如果定义全局变量来实现,变量就不属于函数本身,不在仅受函数控制,给程序维护带来不便;仅对当前文件可见,其他文件不可访问,其他文件可以定义与其同名的变量,两者互不影响。在定义不需要与其他文件共享的全局变量时,加上static关键字能够有效地降低程序模块之间的耦合,避免不同文件同名变量的冲突,且不会误使用。只能在声明它的文件可见,其他文件不能引用该函数。定义在函数体外部,在静态区分配存储空间,编译器自动对其初始化。
2023-01-07 11:06:49 285
原创 FTP协议原理简析
当客户在需要数据的情况下,会告知服务器用什么方式联机,如果是主动式(Active),客户端随机启用一个端口(port BB),通过命令通道告知FTP服务器,等待FTP服务器联机;如图所示,客户端会随机取一个大于1024以上的端口(port AA)来与FTP服务器端的port21达成联机,这个过程为三次握手,达成联机后用户便可以对FTP下达指令,包括查询文件名、下载、上传等指令;FTP服务器由命令通道了解客户端的需求后,主动由20端口向客户端的port BB进行三次握手联机。与主动联机图第一步相同;
2023-01-07 10:52:41 877
原创 GET和POST方法的区别
一般认为POST在传输数据时更加的安全,因为,所以更安全。浏览器由于规范问题不会在GET的请求体中添加数据,但是可以通过例如Fiddler的Composer来添加数据到GET的请求体种。常见的GET和POST区别还有GET传输的数据比较少,POST传输数据多;因此不管GET还是POST,数据传输大小都会有限制,只是POST的传输大小相对于GET来说比较大;数据量大小也并不是面试官期望听到的回答。GET请求多是用来获取数据的,通常可以缓存。
2023-01-07 10:46:53 476
原创 从对称加密和非对称加密讲解HTTP到HTTPS的发展思路
解决中间人攻击的方法是通过受信任的第三方交换公钥,具体做法就是服务器不直接向客户端发送公钥,而是要求受信任的第三方,也就是证书认证机构 (Certificate Authority, 简称 CA)将公钥合并到数字证书中,然后服务器会把公钥连同证书一起发送给客户端,私钥则由服务器自己保存以确保安全。因为每一家CA机构都会给成千上万的网站制作证书,假如攻击者知道abc.com使用的是某家CA机构的证书,那么他也可以同样去这家CA机构申请一个合法的证书,然后在浏览器请求abc.com时对返回的。
2022-12-11 17:02:07 747 1
原创 详解HTTP1.0、1.1、2.0版本区别/优化
HTTP/1.1并不支持 HTTP 首部压缩,为此 SPDY 和 HTTP/2 应运而生, SPDY 使用的是通用的DEFLATE 算法,而 HTTP/2 则使用了专门为首部压缩而设计的 HPACK 算法。本质上是为了减少请求,通过多个js或css合并成一个文件,多张小图片拼合成Sprite图,可以让多个HTTP请求减少为一个,减少额外的协议开销,而提升性能。连接和并行发送请求,这样每次一个请求都需要三次握手,而且其实建立连接和释放连接的这个过程是最耗时的,传输数据相反却不那么耗时。的缓存机制失效的问题。
2022-11-21 11:05:29 5022
原创 DNS协议
一个主机通过DNS获取指定主机名对应的IP地址并发起HTTP的TCP连接的过程:**(1)浏览器**截取URL中的主机名字段**,**发送给DNS应用的客户端**;(2)**DNS客户端向DNS服务器发送**一个包含主机名的**请求**;(3)**DNS客户端收到**来自DNS服务器发出的**回答报文**,该报文中包**含对应请求主机名对应的IP地址**;(4)**浏览器接收到**来自DNS的该**IP地址**(5)**浏览器向**位于**该IP地址80端口的HTTP服务器进程发起一个TCP连接
2022-11-21 11:01:11 2098
原创 A、B机器正常TCP连接后,B突然断网,A处于什么状态?
几个思考点:是否开启keepalive?是否存在数据交互?进程崩溃;客户端主机宕机(客户端网络不可用 是同种情况);①②使用 kill -9 来模拟进程崩溃的情况,发现在 kill 掉进程后,服务端会发送 FIN 报文,与客户端进行四次挥手。所以,即使没有开启 TCP keepalive,且双方也没有数据交互的情况下,如果其中一方的进程发生了崩溃,这个过程操作系统是可以感知的到的,于是就会发送 FIN 报文给对方,然后与对方进行 TCP 四次挥手。
2022-11-21 10:58:26 644
原创 NAT地址转换
同时,又可隐藏网络内部的所有主机,有效避免来自internet的攻击。是指将内部网络的私有IP地址转换为公用IP地址时,IP地址是不确定的,是随机的,所有被授权访问上Internet的私有IP地址可随机转换为任何指定的合法IP地址。2.安全防护:NAT 之内的 PC 联机到 Internet 上面时,他所显示的 IP 是 NAT 主机的公共 IP,所以 Client 端的 PC 当然就具有一定程度的安全了,外界在进行 portscan(端口扫描) 的时候,就侦测不到源Client 端的 PC。
2022-11-21 10:53:18 537
原创 MTU & TTL & RTT
往返时延(Round-Trip Time,RTT)也是一个重要的性能指标,它表示从发送方发送数据开始,到发送方收到来自接收方的确认,总共经历的时延。排队时延是分组在所经过的网络结点的缓存队列中排队所经历的时延,排队时延的长短主要取决于网络中当时的通信量,当网络的通信流量大时,排队时间就长,极端情况下,当网络发生拥塞导致分组丢失时,该结点的排队时延视为无穷大。处理时延是分组在中间结点的存储转发过程中而进行的一些必要的处理所花费的时间,这些处理包括提取分组的首部,进行差错校验,为分组寻址和选路等。
2022-11-21 10:51:47 552
原创 TCP沾包问题
先来解释一下什么是粘包?所谓粘包就是连续给对端发送两个或者两个以上的数据包,对端在一次收取中收到的数据包数量可能大于 1 个,当大于 1 个时,可能是几个(包括一个)包加上某个包的部分,或者干脆就是几个完整的包在一起。当然,也可能收到的数据只是一个包的部分,这种情况一般也叫半包。粘包示意图如下:
2022-11-21 10:49:04 959
原创 TCP和UDP的优缺点比较
TCP的优点:可靠,稳定 TCP的可靠体现在TCP在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口(流量控制)、(超时)重传、拥塞控制机制,在数据传完后,还会断开连接用来节约系统资源。TCP的缺点:慢,效率低,占用系统资源高,易被攻击:TCP在传递数据之前,要先建连接,这会消耗时间,TCP首部大小本身就比UDP首部大,而且在数据传递时基于TCP首部中信息进行的确认机制、重传机制、拥塞控制机制等都会消耗大量的时间,另外还要维护需要保持的传输连接;事实上,每个连接都会占用系统的CPU、内存
2022-11-21 10:46:20 1804
原创 TCP四次挥手 & 2MSL & TIME_WAIT详解
4次握手的最后一个ACK是是由主动关闭方发送出去的,若这个ACK丢失,被动关闭方会再次发一个FIN过来。若主动关闭方能够保持一个2MSL的TIME_WAIT状态,则有更大的机会让丢失的ACK被再次发送出去。(2)防止lost duplicate对后续新建正常链接的传输造成破坏。lost duplicate在实际的网络中非常常见,经常是由于路由器产生故障,路径无法收敛,导致一个packet在路由器A,B,C之间做类似死循环的跳转(也有可能是网络时延导致)。IP头部有个TTL,限制了一个包在网络中的
2022-11-21 10:44:04 1200
原创 详解TCP为什么不能是两次握手
为了确保链路的可靠性,两次握手的过程并不能确保链路以及可靠的建立。这时因为C端和S端并不是一方发送之后就可以确认自己可以正常发送,它们之间隔着网络环境,真正能够确认自端可以正常发送需要依靠对端返回的确认,即ACK。下面具体分析三次握手过程中通信双端的确认状态,?表示未知,✔表示可以确定没有问题:
2022-11-21 10:35:16 3426
原创 OSI 7层模型 & TCP/IP协议首部封装格式解析
物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流(就是由1、0转化为电流强弱来进行传输,到达目的地后再转化为1、0,也就是我们常说的数模转换与模数转换)。这一层的数据叫做比特。数据链路层:定义了如何让格式化数据以帧为单位进行传输,以及如何让控制对物理介质的访问。这一层通常还提供错误检测和纠正,以确保数据的可靠传输。如:串口通信中使用到的115200、8、N、1(端到端)网络层:为在位于不同地理位置的网络中的两个主机系统之间提供连接和路径选择。
2022-11-21 10:27:27 850
原创 C++虚函数表的底层原理 & 到底有几张虚函数表? & 虚函数表是怎么维护的?
昨天读了陈皓前辈博客中关于虚函数表底层原理的一篇博客,本着实践出真知的出发点,遂写了相应的测试代码去检验,发现最后测试出来的结果和陈皓博客中说明的情况存在出入。目前尚不清楚是不同编译器底层实现原理不同还是整个标准已经迭代(距离那篇博客的发布时间已经过去15年了),欢迎一样有求知欲的伙伴同僚也把代码拿去测试,一起分享心得!
2022-08-19 17:31:23 665 2
原创 二级指针分析 -- (int *)*(&b)
可以看出来,类似(int )(&b)这样的操作,主要是通过二级指针访问一级指针存储内容 ,上示代码中关于ptr和ptr2的相关操作解释:1. (int *)(ptr2)是指二级指针中存放的一级指针的地址;2. * 是取出 一级指针的地址 上的值,也就是一级指针本身存储的值;3.(int *)是将从一级指针取到内容指针化,因为是一级指针存储的还是一块地址,否则直接按cout输出会输出整型 。.........
2022-08-19 01:14:16 275
原创 一台Linux机器上最多能建立多少个TCP连接?
但是就目前的TCP协议来说,显然这是不可能的,首先,不会有一台机器可以占用所有的ip,其次需要考虑机器是否能正常的打开2^16个端口,以及机器是否支持那么多的打开文件,最最最重要的是,机器能否有那么大的内存和CPU资源来维护这些TCP连接。ip(ipv4)数量的理论最大值,受限于ip的位数 ---- ip长度为32位,那么极限最优条件下(但没有这个可能)单机可以拥有2^32个ip地址,但这样就把世界上所有的ip都用光了。假如是4GB的内存,那么大约可接受的TCP连接数量是100万左右。.........
2022-08-12 21:40:21 1621
原创 C++中的各种“虚“-- 虚函数、纯虚函数、虚继承、虚基类、虚析构、纯虚析构、抽象类讲解
C++中的一些重要概念都与“虚”相关,比如:① 虚基类、虚继承、虚基类指针(vbptr)、虚基类表(vbtable);② 虚函数、纯虚函数、虚函数指针(vfptr)、虚函数表(vftable)、抽象类、虚析构、纯虚析构。这里对上面罗列出的概念做一个总结,争取把这些都一次讲清楚:......
2022-07-29 16:29:17 1382 2
原创 浅记对于select多路IO网络模型性能调优和BUG解决方案
前些日子接手了一个老项目,是一个网络收发的linux socket程序,接收各地设备发来的数据,进行解码 – 处理数据 – 存数据 – 发数据的工作;项目代码业务逻辑处理没有问题,问题在于该代码运行一阵子之后就收不到数据了,但是进程仍然在跑,且用top命令查看cpu占用率极高,严重影响了云服务器的性能,分析之后,记录调优和debug的心得:这个程序采用了跨平台的多路IO转接函数 —— ,由于select函数设计的比较早,遗留了针对小规模多路IO的性能低下的问题,解决办法是通过用户代码逻辑添加一个额外的数组(
2022-06-12 19:45:07 371
原创 浅记线程池模型中多个线程对同个fd接收缓冲区读取争夺的方案
最近在复习实现和思考线程池的时候发现了一个问题:概括说就是 线程池+多路IO(epoll ET)+ 非阻塞轮询处理数据的场景下,同个fd(socket)高频率接收数据,可能导致线程池中多个线程争夺读取该fd接收缓冲区的情况,怎么处理?思考后得到如下的解决方案:............
2022-06-12 19:14:24 730 3
原创 Epoll 反应堆模型核心原理及代码讲解
epoll反应堆模型的三个要素:epoll ET模式非阻塞轮询处理结构体中联合体中的指针 – 实现回调机制socket、bind、listen – epoll_create 创建监听 红黑树 – 返回 epfdepoll_ctl() 向红黑树上添加一个listenfd(监听socket)while(1) {【可选】每轮迭代监测100个连接,若存在超时连接(沉积用户)则主动关闭; 监听 --> 对应监听fd有事件产生 --> 返回监听满足结构集 (即结构体数组);判断返回数组元素 :}
2022-06-08 19:23:25 738
原创 Epoll 原理及应用 && ET模式与LT模式
epoll是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率,因为它会复用文件描述符集合来传递结果而不用迫使开发者每次等待事件之前都必须重新准备要被侦听的文件描述符集合,另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。目前epell是linux大规模并发网络程序中的热门首选模型。epoll除了提供select/poll那种IO事件的电平触
2022-06-08 19:17:57 549
原创 简单封装一个linux socket服务端的listenfd初始化函数
简单封装一个linux socket服务端的listenfd初始化函数,方便快速调用:initlistensocket()参数说明 —— 服务器开启的监听端口 —— listen()函数的连接队列容量(两队列总容量) —— 置1则listenfd设为非阻塞,置0则默认阻塞initlistensocket()返回值暂时未做出错处理,initlistensocket()函数返回socket()函数的返回值,成功调用的情况下返回监听文件描述符......
2022-06-08 15:33:10 341
原创 可扩/减容线程池C语言原理讲解及代码实现
客户端相当于生产者,服务端相当于消费者。线程池相比较于传统的多线程模型,每次创建线程和销毁线程的开销是可以被节省的。故放弃每来一个请求就创建一个线程的机制,采用一次性批量产生线程的方式。所谓线程“池”,这个池是一个虚拟的概念,指的是产生的线程被保存在的可访问地址。当没有任务时,线程池里的线程都阻塞()在的条件变量上;当有客户端发来了任务/请求,server需要去唤醒池中的线程:被唤醒的线程从任务队列中取出任务并完成处理后,重新回到线程池中等待任务,即等待被唤醒。多路IO转接处理的是客户端怎么去和服务器建立
2022-06-05 20:40:18 852
原创 C/C++ 32位浮点型float转16进制并用字符串输出,简洁明了
C/C++ 32位浮点型float转16进制并用字符串输出C 语言中,指针地址就是IEEE 754 16进制编码,C可以直接调用就不用写函数计算了,C++也是一样的。联合体共用一段内存,可以用一个包含float和char[4]的联合体,给float赋值,然后打印4个char就行;提供一个在线转换工具:在线进制转换(支持在2~36进制之间进行任意转换)代码32位浮点型float(字符串形式)转16进制并用字符串输出#include <stdio.h>#include <s
2022-04-06 18:14:20 7645
原创 C语言用read封装/实现一个readline函数,读取文件一行 or 最后一行
#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <sys/types.h>#include <string.h>#include <fcntl.h>/* 读取fd的一行内容 */ssize_t readline(int fd, char *buf, ssize_t maxlen){ ssize_t count = 0; memset(
2022-04-05 22:19:29 3458
原创 C++实现string输出char的二进制 && string按二进制位转char类型
C++实现string输出char的二进制 && 二进制string按位转char类型string按二进制位转char类型string输出char的二进制string按二进制位转char类型示例代码:#include <string>#include <iostream>using namespace std; /* 8 Bytes 以0/1为内容的字符串按二进制转化成 1 Byte 的 char */int bin_to_dec_once(stri
2022-03-31 23:55:10 2158
原创 Linux Shell脚本 && Linux C程序 获取指定的范围内 or 系统可用端口
这里写目录标题Linux Shell脚本 && Linux C程序 获取指定的范围内 or 系统可用端口一、源代码及其运行1. Linux C程序getPort.c源码运行示例2. 脚本文件 getPort.sh源码运行示例二、bash命令说明1. netstat命令2. awk命令3. wc 命令4. shuf命令Linux Shell脚本 && Linux C程序 获取指定的范围内 or 系统可用端口一、源代码及其运行1. Linux C程序getPort.c源码
2022-03-14 19:20:31 743
转载 Linux 查看 && 修改端口范围限制
1.显示当前临时端口的范围:sysctl net.ipv4.ip_local_port_range或 cat /proc/sys/net/ipv4/ip_local_port_range一般情形下:linux临时端口号范围是(32768,61000)2.暂时性修改临时端口的范围:#echo 1024 65535 > /proc/sys/net/ipv4/ip_local_port_range或者 sudo sysctl -w net.ipv4.ip_local_port_range
2022-03-14 16:24:43 9860
原创 Linux C程序获取本机可用IP地址 && Linux C程序获取system()函数的标准输出到char *缓冲中
Linux C程序获取本机可用IP地址 &&Linux C程序获取system()函数的标准输出到char *缓冲中方法一:使用pipe匿名管道思路:fork一个子进程,并创建一个匿名管道,在子进程中执行shell命令,并将其标准输出dup到匿名管道的输入端,父进程从管道 中读取,即可获得shell命令的输出。char * get_ipaddr(){ int fd[2]; pipe(fd); int pid = fork();
2022-03-12 23:13:02 5126
原创 double类型打印结果一致但系统判定不一致的问题
假设存在两个理论结果一致的公式b和b1:b和b1的计算方式理论上计算得出的结果是一样的,编译器打印出来肉眼看也是一样的,系统判定不一样原因如下:即使double有着很高的精度(64位),但是机器对最后一位的处理必定是四舍五入的;如遇到无限循环or无限不循环小数这样的计算结果,若将该结果保存在某个double变量中用于后续计算,计算结果的判断可能会出错。那么有以下几种处理方式:(1)将double强制转换为string,保留精度在十进制0.000001(2)检测差值,当差值小于0.00000
2022-03-05 14:10:43 943
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人