作用:
GET是用来获取资源的,POST是用来传输实体主体的。
参数:
GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在实体主体中。
安全性:
GET 方法是安全的,而 POST 却不是,因为 POST 的目的是传送实体主体内容,这个内容可能是用户上传的表单数据,上传成功之后,服务器可能把这个数据存储到数据库中,因此状态也就发生了改变。
安全的方法除了 GET 之外还有**:HEAD、OPTIONS**。
不安全的方法除了 POST 之外还有 PUT、DELETE。
幂等性:
幂等的 HTTP 方法,同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也是一样的。换句话说就是,幂等方法不应该具有副作用(统计用途除外)。所有的安全方法也都是幂等的。
GET /pageX HTTP/1.1 是幂等的,连续调用多次,客户端接收到的结果都是一样的
POST /add_row HTTP/1.1 不是幂等的,如果调用多次,就会增加多行记录
可缓存性:
请求报文的 HTTP 方法本身是可缓存的,包括 GET 和 HEAD,但是 PUT 和 DELETE 不可缓存,POST 在多数情况下不可缓存的。
响应报文的状态码是可缓存的,包括:200, 203, 204, 206, 300, 301, 404, 405, 410, 414, and 501
XMLHttpRequest:
在使用 XMLHttpRequest 的 POST 方法时,浏览器会先发送 Header 再发送 Data。但并不是所有浏览器会这么做,例如火狐就不会。
而 GET 方法 Header 和 Data 会一起发送。
进程是具有一定功能的一个程序关于某一个数据集进行的一次运行活动,是系统进行资源分配和调度的基本单位。线程是进程的一个实体,是CPU进行调度和分配的基本单位。一个进程里面可以拥有很多个线程,线程不拥有系统资源,但是线程会有一些运行不可缺少的资源,比如程序计数器,寄存器以及堆栈,以此同时,同一进程中的线程共享进程中的资源。进程的创建和销毁,系统的开销非常大,但是,线程的创建和销毁的开销比较小。
进程同步与进程通信很容易混淆,它们的区别在于:
进程同步:控制多个进程按一定顺序执行;
进程通信:进程间传输信息。
进程通信是一种手段,而进程同步是一种目的。也可以说,为了能够达到进程同步的目的,需要让进程进行通信,传输一些进程同步所需要的信息。
1 管道 :
管道是通过调用 pipe 函数创建的,fd[0] 用于读,fd[1] 用于写。
#include
int pipe(int fd[2]);
它具有以下限制:
只支持半双工通信(单向交替传输);
只能在父子进程或者兄弟进程中使用。
2 FIFO:
也称为命名管道,去除了管道只能在父子进程中使用的限制。
3 消息队列:
相比于 FIFO,消息队列具有以下优点:
1 消息队列可以独立于读写进程存在,从而避免了 FIFO 中同步管道的打开和关闭时可能产生的困难;
2 避免了 FIFO 的同步阻塞问题,不需要进程自己提供同步方法;
3 读进程可以根据消息类型有选择地接收消息,而不像 FIFO 那样只能默认地接收。
4 信号量:
它是一个计数器,用于为多个进程提供对共享数据对象的访问。
5 共享存储:
允许多个进程共享一个给定的存储区。因为数据不需要在进程之间复制,所以这是最快的一种 IPC。
需要使用信号量用来同步对共享存储的访问。
6 套接字:
与其它通信机制不同的是,它可用于不同机器间的进程通信。
1 临界区:
对临界资源进行访问的那段代码称为临界区。
为了互斥访问临界资源,每个进程在进入临界区之前,需要先进行检查。
2 同步和互斥:
同步:多个进程因为合作产生的直接制约关系,使得进程有一定的先后执行关系。
互斥:多个进程在同一时刻只有一个进程能进入临界区。
3 信号量:
信号量(Semaphore)是一个整型变量,可以对其执行 down 和 up 操作,也就是常见的 P 和 V 操作。
4 管程:
使用信号量机制实现的生产者消费者问题需要客户端代码做很多控制,而管程把控制的代码独立出来,不仅不容易出错,也使得客户端代码调用更容易。
区别:
1 数组的元素个数是固定的,而组成链表的结点个数可按需要增减;
2 数组元素的存诸单元在数组定义时分配,链表结点的存储单元在程序执行时动态向系统申请。
3 数组中的元素顺序关系由元素在数组中的位置(即下标)确定,链表中的结点顺序关系由结点所包含的指针来体现。
优缺点:
1 数组访问元素快,通过下标寻找。链表访问元素慢,需要遍历寻找。
2 数组数组添加元素慢,需要数组在进行移动。链表添加删除元素方便,调整指针就行。
内存:
数组:
在内存中,数组是一块连续的区域。
数组需要预留空间,在使用前要先申请占内存的大小,可能会浪费内存空间
链表:
在内存中可以存在任何地方加粗样式,不要求连续。
不指定大小,扩展方便。链表大小不用定义,数据随意增删。
== 比较的是变量(栈)内存中存放的对象的(堆)内存地址,用来判断两个对象的地址是否相同,即是否是指相同一个对象。比较的是真正意义上的指针操作。
equals:用来比较的是两个对象的内容是否相等;
详解 https://www.cnblogs.com/lhzhou/p/4148782.html
select/poll/epoll 都是 I/O 多路复用的具体实现,select 出现的最早,之后是 poll,再是 epoll。
深入理解epoll的实现原理:
epoll是一种IO多路复用技术,可以非常高效的处理数以百万计的socket句柄,比起以前的select和poll效率高大发了。先简单回顾下如何使用C库封装的3个epoll系统调用吧。int epoll_create(int size); int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout); 使用起来很清晰,
1 首先要调用epoll_create建立一个epoll对象。参数size是内核保证能够正确处理的最大句柄数,多于这个最大数时内核可不保证效果。
2 epoll_ctl可以操作上面建立的epoll,例如,将刚建立的socket加入到epoll中让其监控,或者把 epoll正在监控的某个socket句柄移出epoll,不再监控它等等。
3 epoll_wait在调用时,在给定的timeout时间内,当在监控的所有句柄中有事件发生时,就返回用户态的进程。
epoll比select/poll的优越之处:
select/poll每次调用时都要传递你所要监控的所有socket给select/poll系统调用,这意味着需要将用户态的socket列表copy到内核态,如果以万计的句柄会导致每次都要copy几十几百KB的内存到内核态,非常低效。而我们调用epoll_wait时就相当于以往调用select/poll,但是这时却不用传递socket句柄给内核,因为内核已经在epoll_ctl中拿到了要监控的句柄列表。
所以,实际上在你调用epoll_create后,内核就已经在内核态开始准备帮你存储要监控的句柄了,每次调用epoll_ctl只是在往内核的数据结构里塞入新的socket句柄。
应用场景:
只需要运行在 Linux 平台上,有大量的描述符需要同时轮询,并且这些连接最好是长连接。
http报文分为 请求报文 和响应报文。
HTTP 请求报文格式:
HTTP 请求报文主要由请求行,请求头部,请求正文3部分组成:
1 ,请求行
由3部分组成,分别为:请求方法,URL(见备注1 )以及协议版本,之间由空格分隔
请求方法包括GET,HEAD,PUT,POST,TRACE,OPTIONS,DELETE以及扩展方法。
GET 方法是默认的HTTP请求方法,我们日常用GET方法来提交表单数据,然而用GET方法提交的表单数据只经过了简单的编码,同时它将作为URL的一部分向网站服务器发送,因此,如果使用GET方法来提交表单数据就存在着安全隐患上。
POST 方法是GET方法的一个替代方法,它主要是向Web服务器提交表单数据,尤其是大批量的数据.POST方法克服了GET方法的一些缺点。通过POST方法提交表单数据时,数据不是作为URL请求的一部分而是作为标准数据传送网络服务器,这就克服了GET方法中的信息无法保密和数据。因此,出于安全的考虑以及对用户隐私,通常表单提交时采用POST方法。
协议版本的格式为:HTTP /。主版本号次版本号,常用的有HTTP / 1.0和HTTP / 1.1
HTTP1.0 和HTTP1.1的区别:
1)在HTTP1.0协议中,客户端与网络服务器建立连接后,短连接。
2)HTTP1.1 协议,允许客户端与网络服务器建立连接后,在一个连接上获取多个网络资源。(长连接)
2 请求头部
为请求报文添加了一些附加信息,由“名/值”对组成,每行一对,名和值之间使用冒号分隔
常见请求头如下:
3 ,请求正文
HTTP 响应报文格式:
HTTP 响应报文主要由状态行,响应头部, 响应正文 3部分组成。
1 ,状态行
由3部分组成,分别为:协议版本,状态码,状态码描述,之间由空格分隔
状态代码为3位数字,200〜299的状态码表示成功,300〜399的状态码指资源重定向,400〜499的状态码指客户端请求出错,500〜599的状态码指服务端出错( HTTP / 1.1向协议中引入了信息性状态码,范围为100〜199)
2 ,响应头部
与请求头部类似,为响应报文添加了一些附加信息
3 、响应正文
UDP 和 TCP 的特点:
1、 用户数据报协议 UDP(User Datagram Protocol)是无连接的,尽最大可能交付,没有拥塞控制,面向报文(对于应用程序传下来的报文不合并也不拆分,只是添加 UDP 首部),支持一对一、一对多、多对一和多对多的交互通信。
2、 传输控制协议 TCP(Transmission Control Protocol)是面向连接的,提供可靠交付,有流量控制,拥塞控制,提供全双工通信,面向字节流(把应用层传下来的报文看成字节流,把字节流组织成大小不等的数据块),每一条 TCP 连接只能是点对点的(一对一)。
UDP 首部格式:
首部字段只有 8 个字节,包括源端口、目的端口、长度、检验和。12 字节的伪首部是为了计算检验和临时添加的。
TCP 首部格式:
序号 :用于对字节流进行编号,例如序号为 301,表示第一个字节的编号为 301,如果携带的数据长度为 100 字节,那么下一个报文段的序号应为 401。
确认号 : 期望收到的下一个报文段的序号。例如 B 正确收到 A 发送来的一个报文段,序号为 501,携带的数据长度为 200 字节,因此 B 期望下一个报文段的序号为 701,B 发送给 A 的确认报文段中确认号就为 701。
**数据偏移 :**指的是数据部分距离报文段起始处的偏移量,实际上指的是首部的长度。
确认 ACK : 当 ACK=1 时确认号字段有效,否则无效。TCP 规定,在连接建立后所有传送的报文段都必须把 ACK 置 1。
同步 SYN : 在连接建立时用来同步序号。当 SYN=1,ACK=0 时表示这是一个连接请求报文段。若对方同意建立连接,则响应报文中 SYN=1,ACK=1。
终止 FIN :用来释放一个连接,当 FIN=1 时,表示此报文段的发送方的数据已发送完毕,并要求释放连接。
窗口 : 窗口值作为接收方让发送方设置其发送窗口的依据。之所以要有这个限制,是因为接收方的数据缓存空间是有限的
TCP与UDP区别总结:
1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达; UDP尽最大努力交付,即不保 证可靠交付
3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
4、每一条TCP连接只能是点到点的; UDP支持一对一,一对多,多对一和多对多的交互通信
5、TCP首部开销20字节;UDP的首部开销小,只有8个字节
6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
先对new和delete简单进行一下总结,然后再细说new和malloc的区别。
一、new和delete
C语言提供了malloc和free两个系统函数,完成对堆内存的申请和释放。而 C++ 则提供了两个关键字new和delete;
1.1 规则
1、**new/delete是关键字,效率高于malloc和free。
2、 配对使用,避免内存泄漏和多重释放。
3、 避免交叉使用,比如malloc申请空间delete释放,new出的空间被free。
4、 new/delete 主要是用在类对象的申请和释放**。申请的时候会调用构造器完成初始化,释放的时候,会调用析构器完成内存清理。
二、new和malloc的区别
2.1 属性
new和delete是C++关键字,需要编译器支持;malloc和free是库函数,需要头文件支持。
2.2 参数
使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算。而malloc则需要显式地指出所需内存的尺寸。
2.3 返回类型
new操作符内存分配成功时,返回的是 对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。 而malloc内存分配成功则是返回void *** ,需要通过强制类型转换将void*指针转换成我们需要的类型**。
2.4 自定义类型
new会先调用operator new函数,申请足够的内存(通常底层使用malloc实现)。然后调用类型的构造函数,初始化成员变量,最后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数释放内存(通常底层使用free实现)。
malloc/free是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。
2.5 重载
C++允许重载new/delete操作符,malloc不允许重载。
2.6 内存区域
new做两件事:分配内存和调用类的构造函数,delete是:调用类的析构函数和释放内存。而malloc和free只是分配和释放内存。
new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。而堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。自由存储区不等于堆,如上所述,布局new就可以不位于堆中。
2.7 分配失败
new内存分配失败时,会抛出bac_alloc异常。malloc分配内存失败时返回NULL。
2.8 内存泄漏
内存泄漏对于new和malloc都能检测出来,而new可以指明是哪个文件的哪一行,malloc确不可以。
https://blog.csdn.net/bolinzhiyi/article/details/104984885
1. 管理方式不同:
2. 空间大小不同:
3. 能否产生碎片不同:
4. 生长方向不同:
5. 分配方式不同:
6. 分配效率不同:
从这里我们可以看到,堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。所以栈在程序中是应用最广泛的,就算是函数的调用也利用栈去完成,函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。所以,我们推荐大家尽量用栈,而不是用堆。
流程概况:将源代码转换成机器可识别代码的过程,编译程序读取源代码,对他进行词法和语法的分析,将高级语言转化为功能等效的汇编代码,然后转化为机器语言,按照操作系统对可执行文件格式的要求连接生成可执行程序
源程序->编译预处理->编译->汇编程序->链接程序->可执行文件
1)预处理阶段
预处理器(cpp)对源程序中以 #开头的命令进行处理 ,例如将#include命令后面的.h文件内容插入程序文件。输出结果是一个以.i为扩展名的源文件hello.i。
读取源代码,对其中的伪指令(#开头)和特殊符号进行处理.主要包括:
宏定义
#define Name TokenString :将所有Name替换成TokenString
#undef: 取消宏定义
条件编译
#ifdef,#ifudef,#else,#elif,endif等等
这些伪指令让程序员通过不同的宏决定编译程序对那些代码进行处理,从而把不必要的代码过滤掉
头文件包含指令
#include “FileName”,#include
特殊符号
预编译可以处理一些特殊符号,比如LINE是当前的行号(十进制),FILE是当前源程序的名称.预编译会识别这些特殊符号.
2)编译阶段
编译器(ccl)对预处理后的源程序进行编译,生成一个汇编语言程序hello.s。汇编语言源程序中的每一条语句都以一种文本格式描述了一条低级指令。
3)汇编阶段
汇编器(as)将hello.s 翻译成机器语言指令,把这些指令打包成一个称为可重定位目标文件的hello.o,一种二进制文件,用文本编辑器打开会乱码。
4)链接阶段
链接器(ld)将多个可重定位目标文件和标准库函数合并为一个可执行目标文件, 或简称可执行文件。
我们大家在编程过程中对“链接”这个词并不陌生,链接所解决的问题即是将我们自己写的代码和别人写的库集成在一起。链接可以分为静态链接与动态链接,下文将分别讲解这两种方式的特点与其区别。
1、静态链接
1)特点:在生成可执行文件的时候(链接阶段),把所有需要的函数的二进制代码都包含到可执行文件中去。因此,链接器需要知道参与链接的目标文件需要哪些函数,同时也要知道每个目标文件都能提供什么函数,这样链接器才能知道是不是每个目标文件所需要的函数都能正确地链接。如果某个目标文件需要的函数在参与链接的目标文件中找不到的话,链接器就报错了。目标文件中有两个重要的接口来提供这些信息:一个是符号表,另外一个是重定位表。
2) 优点:在程序发布的时候就不需要的依赖库,也就是不再需要带着库一块发布,程序可以独立执行。
3)缺点: 程序体积会相对大一些。 如果静态库有更新的话,所有可执行文件都得重新链接才能用上新的静态库。
2 、动态链接
1)特点: 在编译的时候不直接拷贝可执行代码,而是通过记录一系列符号和参数,在程序运行或加载时将这些信息传递给操作系统,操作系统负责将需要的动态库加载到内存中,然后程序在运行到指定的代码时,去共享执行内存中已经加载的动态库可执行代码,最终达到运行时连接的目的。
2)优点: 多个程序可以共享同一段代码,而不需要在磁盘上存储多个拷贝。
3)缺点: 由于是运行时加载,可能会影响程序的前期执行性能。
上面的文章多次提到库(lib)这个概念,所谓的库就是一些功能代码经过编译连接后的可执行形式。