博客连接javascript
基本数据类型html
// 整数 byte 1 short 2 int 4 long 8 // 浮点数 float 4 double 8 // 逻辑 boolean 1 // 字符 char 2, Unicode
引用类型的变量, 在堆, 变量只是引用, 相似于指针, 只能指向特定对象, 不能乱指, 复制变量的时候, 复制的是引用前端
引用类型: 数组, 类, 接口vue
抽象类跟接口的区别java
JavaNotesnode
抽象类和接口的区别python
抽象类, 是声明, 抽象类不能instantiate(实例化), 也就是不能制造对象。抽象方法只声明, 不实现。具体的实现由继承它的子类来实现。linux
public abstract class Shape{ // 抽象的方法, 注意没有大括号, ()后面直接分号结尾 // 有abstract方法的类必须是abstract public abstract void draw(); }
接口, 让其余类可以有接口的方法ios
public interface Cell{ // 不须要显示写abstract void draw(Graphics g, int x, int y, int size); } public class Fox extends Animal implements Cell{ @Override public void draw(...){ // ... } public void run() { } }
抽象类能够有非抽象的方法(具体实现), 接口是纯抽象类, 只有抽象方法git
一个子类只能存在一个父类, 可是能够存在多个接口。
M, Model, 模型, 保存和维护数据, 还能够 通知 View 进行界面的更新.
V, View, 表现, 从 Model 得到数据, 并以此画出表现(界面). View 是被动的, 只有在 Model 通知 View 以后, View才会去Model取数据, 并画出来.
C, Control, 控制, 获得用户输入, 以此调整数据. C 和 V 并不直接交互. C只能更新Model中的数据, 也就是说, 用户在界面上所做的操做, 不会直接修改界面上的显示. 而是先去修改后台的数据, 再由Model通知View, 再总体重画.
start(), run(), stop(), destroy()
新建 --- 就绪 --- 运行 --- 阻塞 --- 运行 --- 终止
分类
ArrayIndexOutOfBoundsException OpenFileException AllocateMemoryException LoadFileException OutOfMemoryError
处理方式
try{ } catch(ArrayIndexOutOfBoundsException e){ }
某个对象在将来的程序运行中, 将不会被访问, 就能够回收它的内存
引用计数收集器, 当有其余数据与其相关时则加一, 反之相关解除时减一, 最后计数为 0 的对象能够回收
跟踪收集器, 按期对若干根储存对象开始遍历, 对与其相关的对象进行标记, 最后, 没有被标记的对象就能够回收
局部变量, 函数参数
全局变量, 静态全局变量, 静态局部变量
若没有手动初始化, 则会自动初始化为0
new --- delete / malloc --- free
存放字符串常量和const修饰的全局变量
预处理 --- 编译 --- 汇编 --- 连接 --- 装载 --- 运行
malloc, 分配内存, 是在 运行
这一阶段。即在 heap 上动态分配
指向二维数组的指针
int a[4][2]; int (*p) [2]; p = a; p[3][1];
[]
的优先级高于 *
, 因此要加括号
二级指针
void getMemory(char **p){ *p = (char *)malloc(100); } int main(){ char *str = NULL; getMemory(&str); strcpy(str, "Thurs"); strcat(str+2, " day"); printf("%s\n", str); return 0; }
首先 str
被分配了100字节的空间, 而后在 str 开头粘贴了 Thurs
, 接着, 因为 strcat
老是先找到末尾再粘贴, 因此 day
不会覆盖 urs
正数与原码和反码相同。对于负数, 以 -1
为例
1)先写出原码, `1000 0001` 2)符号位不变, 其他各位取反, `1111 1110` 3)最后 +1, `1111 1111`
数据类型在内存中的表达形式
整数:二进制数(补码), 能够直接在加法器里面作加法 浮点数:要进行编码
结构体内定义指针
typedef struct{ int val; struct Node *lchild, *rchild; }Node; Node root = {1, NULL, NULL};
struct node{ int val; struct Node *lchild, *rchild; }; struct node root = {1, NULL, NULL};
const
在 *
以前, 意思是对 i
只读
/* const 在 * 以前, 意思是 对 i 只读 ** 能够经过 *p 读取i的值, 但不能经过 *p 修改i的值 ** 另外, 指针做为函数参数时, 这样写 (const int * p) */ int i = 1; const int * p1 = &i; int const * p2 = &i;
const 在 * 的后面, 意思是 指针 不能指向其余地址
/* const 在 * 的后面, 意思是 指针 不能指向其余地址 ** p3 被绑定到了 j, 就没法再指向其余地址 ** 能够经过p3来读写j的值 */ int j = 2; int * const p3 = &j; *p3; // ok *p3 = 3; // ok int k = 123; p3 = &k; // error
用法
int *a = (int *)malloc( 10*sizeof(int) )
man malloc
能够看到参数要求是(size_t size)
, 因此实参是(10*sizeof(int))
, 表示申请到了10*4=40
个字节的空间, 一样的也能够40*sizeof(char)
, 或者直接写40
能够看到返回类型是 void *
, 这也就解释了为何要在前面加上(int *)
, 由此划分空间, 来区分类型
sizeof()
是静态的, 程序编译完成后已经定下来, 直接填进去了, 并不会真的去作计算
int a = 1; printf("%d\n", sizeof(a++)); // 4 printf("%d\n", a); // 1, sizeof()是静态的, 程序编译完成后已经定下来, 直接填进去了, 并不会真的去作a的++ printf("%d\n", sizeof(a + 2.0));// 8, 已经转换成了double printf("%d\n", sizeof(double)); // 8 return 0;
define
宏是在预处理阶段展开, const
常量是编译运行阶段使用.
define宏没有类型, 不作任何类型检查, 仅仅是展开. const常量有具体的类型, 在编译阶段会执行类型检查.
define宏仅仅是展开, 有多少地方使用, 就展开多少次, 不会分配内存. const常量会在内存中分配(堆或栈).
==
做为判断条件virtual
的函数叫作虚函数用于 多态
(即 动态绑定
, 覆盖Override
, 运行的时候根据实例对象来调用方法)
class Animal { public: void run(){ cout << "That animal is running\n"; } virtual void eat(){ cout << "That animal is eating\n"; } }; class Dog : public Animal{ public: void run(){ cout << "The dog is running\n"; } void eat(){ cout << "The dog is eating\n"; } }; int main(){ // 父类 `Animal` 类型的 `指针` 能够管理子类对象 // 若是方法名前面有 virtual, 则能够动态绑定 Animal * animal = new Dog(); animal->run(); // That animal is running, 隐藏子类方法 animal->eat(); // The dog is eating, 子类方法覆盖父类, 多态 // 注意指针才能够, 普通变量形式仍然会隐藏子类方法 Animal ani = Dog(); ani.eat(); // That animal is eating, 隐藏子类方法 return 0; }
父类方法被声明为 virtual
后, 直接/间接子类中的这个方法都会变成 virtual
, 也即子类中的 virtual
能够省略, 但最好仍是写上去
纯虚函数只有声明, 没有实现, 至关于接口规范。含有纯虚拟函数的类称为抽象类, 它不能生成对象(不能放在等号右边), 但能够声明指向实现该抽象类的具体类的指针或引用。
class Flyable { public: virtual void fly() = 0; // 纯虚函数, 只有声明, 后接 = 0 virtual void run() = 0; }; class Bird : public Flyable{ public: void fly(){ cout << "Bird can fly\n"; // 子类只有实现纯虚函数才能实例化 } }; class Superman : public Flyable{ public: void fly(){ cout << "Superman can fly\n"; } void run(){ cout << "Superman is running\n"; } }; int main(){ Flyable * f1 = new Bird(); f1->fly(); // 出错, 由于没有实现全部的纯虚函数, 因此仍然是抽象类, 没法实例化 Flyable f2 = new Superman(); f2->fly(); // Superman can fly return 0; }
定义纯虚函数的目的在于, 使派生类仅仅只是继承函数的接口。纯虚函数的意义, 让全部的类对象(主要是派生类对象)均可以执行纯虚函数的动做, 但类没法为纯虚函数提供一个合理的缺省实现。因此类纯虚函数的声明就是在告诉子类的设计者, “你必须提供一个纯虚函数的实现, 但我不知道你会怎样实现它”。
new
操做符内存分配成功时, 返回的是对象类型的指针, 类型严格与对象匹配, 无须进行类型转换, 故 new
是符合类型安全性的操做符。而 malloc
内存分配成功则是返回 void *
, 须要经过强制类型转换将 void *
指针转换成咱们须要的类型。
类型安全很大程度上能够等价于内存安全, 类型安全的代码不会试图方法本身没被受权的内存区域。关于 C++
的类型安全性可说的又有不少了
+
运算符,从新申请 len1 + len2
的内存空间,而后把 s1, s2
复制进去选择器
// 按ID查找 document.getElementById('xxx'); // 按tagname查找 document.getElementsByTagName('xxx'); // classname document.getElementsByClassName('xxx');
jQuery, 选择器是 jQuery
的核心
// DOM 操做 var ele = document.getElementById('id1'); var divlist = document.getElementsByTagName('div'); // jQuery 的写法 // 返回一个 jQuery 对象, 即若 id1 存在, 那么返回 [<div id="id1">...</div>] // 若不存在, 则返回 [] var ele = $('#id1'); // jQuery 对象和 dom 对象相互转化 var eledom = ele.get(0); ele = $(eledom); // 按 class 查找 var a = $('.red.green'); // 多个 class 时中间没有空格 // 按属性查找 var email = $('[name=email]'); // 找出<??? name="email"> var passwordInput = $('[type=password]'); // 找出<??? type="password"> var icons = $('[name^=icon]'); // 找出全部name属性值以icon开头的DOM var names = $('[name$=with]'); // 找出全部name属性值以with结尾的DOM // 组合查找 var emailInput = $('input[name=email]'); // 找到全部 input 中的 name="email" 的属性 // 不会找出 <div name="email"> // 多项选择器(不会重复选择) $('p,div'); // 把<p>和<div>都选出来 $('p.red,p.green'); // 把<p class="red">和<p class="green">都选出来
正则表达式
`\d` 数字 `\w` 字母或数字 `.` 至少 1 个任意字符 `*` 至少 0 个任意字符 `\d{3}` 匹配 3 个字符 `[0-9a-zA-Z\_]` 匹配一个数字, 字母或者下划线 var re1 = /^\d{11}$/; re1.test('12345678'); // false
AJAX, Asynchronous JavaScript and XML, 意思就是用 JavaScript 执行异步网络请求
AJAX请求是异步执行的, 也就是说, 要经过回调函数得到响应
function success(text) { var textarea = document.getElementById('test-response-text'); textarea.value = text; } function fail(code) { var textarea = document.getElementById('test-response-text'); textarea.value = 'Error code: ' + code; } var request = new XMLHttpRequest(); // 新建XMLHttpRequest对象 request.onreadystatechange = function () { // 状态发生变化时, 函数被回调 if (request.readyState === 4) { // 成功完成 // 判断响应结果: if (request.status === 200) { // 成功, 经过responseText拿到响应的文本: return success(request.responseText); } else { // 失败, 根据响应码判断失败缘由: return fail(request.status); } } else { // HTTP请求还在继续... } } // 发送请求: request.open('GET', '/api/categories'); request.send();
引用计数, del对象
Unix/Linux
推荐多进程, 提供了一个 fork()
系统调用(System call
)
pid = fork()
, 调用一次返回两次, 子进程中返回的 pid == 0
, 父进程中返回的是子进程的 pid > 0
, ppid = getppid()
能够获得父进程的 pid
import os # 获得当前进程的 pid print( os.getpid() ) pid = os.fork() if pid == 0: print('This is child process %s, parent is %s' % (os.getpid(), os.getppid())) else: print('This is parent process %s, child is %s' % (os.getpid(), pid))
结果
17420 This is parent process 17420, child is 17421 This is child process 17421, parent is 17420
Windows
没有 fork()
, Python
多进程须要使用 multiprocessing
from multiprocessing import Process import os def proc(name): print('child process %s, pid = %s' % (name, os.getpid())) p = Process( target=proc, args=('test',) ) print('child process start') p.start() p.join() print('child process end')
结果
child process start child process test, pid = 17491 child process end
建立子进程时, 只须要传入待执行函数 target
和函数的参数, 建立一个 Process
实例, 用 start()
方法启动
join()
方法能够等待子进程结束后再继续往下运行, 一般用于进程间的同步。
多线程. 进程是由若干线程组成的, 一个进程至少有一个线程, 线程是操做系统直接支持的基本执行单元.
启动一个线程就是把一个函数传入并建立 Thread
实例, 而后调用 start()
开始执行
import time, threading def loop(): print('%s is running' % threading.current_thread.name) print( '%s is running' % threading.current_thread().name ) t = threading.Thread(target=func, name='myThread') t.start() t.join() print( '%s ended' % threading.current_thread().name )
多线程共享的内容: 虚拟地址空间,只读代码块,读、写数据, 堆(全局, 静态), 打开的文件集合
锁
balance = 0 def change_balance(n): global balance balance += n balance -= n lock = threading.lock() def run_thread(n): for i in range(10000): # 用以前先得到 balance 等全局变量的独占权 lock.acquire() try: change_balance(n) finally: # 用完后释放锁 lock.release()
Python 动态类型语言, 运行期间才检查数据类型
Java 分号结尾, Python 不须要
结构定义
struct Node{ public: int val; Node * next; Node(int x) : val(x), next(NULL) {} };
插到第 n 个结点前面, n 从 0 开始
Node * insertBefore(Node * head, int n, int val){ Node * p = head; Node * node = new Node(val); if( n == 0 ){ node->next = head; head = node; } else{ --n; while( p != NULL && n > 0 ){ p = p->next; --n; } node->next = p->next; p->next = node; } return head; }
插到第 n 个结点后面, n 从 0 开始
Node * insertAfter(Node * head, int n, int val){ Node * p = head; Node * node = new Node(val); while( p != NULL && n > 0 ){ p = p->next; --n; } node->next = p->next; p->next = node; return head; }
删除第 n 个结点, n 从 0 开始
Node * deleteAt(Node * head, int n){ if( head == NULL ){ return head; } if( n == 0 ){ Node * now = head->next; delete head; return now; } --n; Node * pre = head; Node * now = head->next; while( now != NULL && n > 0 ){ now = now->next; pre = pre->next; n--; } if( now != NULL ){ pre->next = now->next; delete now; } return head; }
功能、性能、空间开销的折中结果。
AVL更平衡,结构上更加直观,时间效能针对读取而言更高;维护稍慢,空间开销较大。
红黑树,读取略逊于AVL,维护强于AVL,空间开销与AVL相似,内容极多时略优于AVL,维护优于AVL。
若是插入一个node引发了树的不平衡,AVL和RB-Tree都是最多只须要2次旋转操做,即二者都是O(1);可是在删除node引发树的不平衡时,最坏状况下,AVL须要维护从被删node到root这条路径上全部node的平衡性,所以须要旋转的量级O(logN),而RB-Tree最多只需3次旋转,只须要O(1)的复杂度。
其次,AVL的结构相较RB-Tree来讲更为平衡,在插入和删除node更容易引发Tree的unbalance,所以在大量数据须要插入或者删除时,AVL须要rebalance的频率会更高。所以,RB-Tree在须要大量插入和删除node的场景下,效率更高。天然,因为AVL高度平衡,所以AVL的search效率更高。
map的实现只是折衷了二者在search、insert以及delete下的效率。整体来讲,RB-tree的统计性能是高于AVL的。
红黑树是 BST,且有以下规则
1) 结点是红色或黑色 2) 根是黑色 3) 叶子是黑色结点(叶子是 NULL) 4) 红结点必有两个黑色孩子,也即,从根到叶子路径上不能有连续的红结点 5) 任一结点向下到叶子的全部路径都包含相同数目的黑色节点(黑高度相同)
递归查找LCA
// LeetCode 235, 236 都适用 TreeNode * lowestCommonAncestor(TreeNode * root, TreeNode * p, TreeNode * q){ if( root == NULL || root == p || root == q ){ return root; } TreeNode * left = lowestCommonAncestor(root->left, p, q); TreeNode * right = lowestCommonAncestor(root->right, p, q); if( left != NULL && right != NULL ){ return root; } else{ return left==NULL ? right : left; } }
冒泡, 最好 O(n), 最坏 O(n^2)
// 升序 void bubble_sort(int a[], int len){ for(int i=0; i < len; i++ ){ for( int j = len - 1; j > i; j-- ){ if( a[j] < a[j-1] ){ swap(a[j], a[j-1]); } } } } int main(){ const int len = 8; int a[len]={4, 2, 5, 1, 3, 2, 5, 1}; bubble_sort(a, len); for( int i = 0; i < len; i++){ cout << a[i] << '\t'; } return 0; }
快排, 最坏 O(n^2), 平均 O(nlgn)
int a[MAXSIZE] = {4, 2, 6, 3, 1, 5, 7}; int partQuickSort(int left, int right){ int i = left, j = right; int key = a[i]; while( i < j ){ while( i < j && a[j] > key ){ j--; } if( i < j ){ // a[j] < key, 换到左边 a[i++] = a[j]; } while( i < j && a[i] < key ){ i++; } if( i < j ){ // a[i] > key, 换到右边 a[j--] = a[i]; } } int mid = i; a[mid] = key; return mid; } /* 以a[left]为中轴key, 把全部小于key的都放到它的左边, 大的放到右边。 中轴的位置就固定了。 再对左边这一块和右边这一块, 作一样的处理。 */ void quickSort( int left, int right ){ if(left < right){ int mid = partQuickSort(left, right); quickSort(left, mid - 1); quickSort(mid + 1, right); } }
插入, 最好 O(n), 最坏 O(n^2)
// 升序 void insert_sort(int a[], int len){ for(int i = 1; i < len; i++ ){ int j = i; int key = a[j]; // 把 key 插到正确的位置 while( j > 0 && a[j-1] > key ){ a[j] = a[j-1]; j--; } a[j]=key; } }
二分, 序列必须有序
// 递归 int bsearch(int a[], int left, int right, int key){ if( left <= right ){ int mid = (left + right) / 2; if( key < a[mid] ){ return bsearch(a, left, mid - 1, key); } else if( key > a[mid] ){ return bsearch(a, mid + 1, right, key); } else{ return mid; } } return -1; } // 非递归 int bsearch(int a[], int left, int right, int key){ while( left <= right ){ int mid = (left + right) / 2; if( key < a[mid] ){ right = mid - 1; } else if( key > a[mid] ){ left = mid + 1; } else{ return mid; } } return -1; }
最大公因数 gcd, 最小公倍数 lcm
// PAT_B_1062, 1034, PAT_A_1081 // 最大公因数, the Greatest Common Divisor int get_gcd(int a, int b){ if( b == 0 ){ return a; } else{ return get_gcd(b, a % b); } } // 最小公倍数, the Lowest Common Multiple int get_lcm(int a, int b){ int gcd = get_gcd(a, b); if( gcd != 0 ){ return a * b / gcd; } else{ return 0; } }
数据库事务(Transaction)的 ACID 特性
原子性(Atomicity), 一致性(Consistency), 隔离型(Isolation), 持久性(Durability)
数据库事务隔离级别有4个
# 由低到高依次为 Read uncommitted, 读到了未提交的事物, 只是 add 尚未 commit Read committed, 读到了上一次的commit, 也就是说尚未更新 最新的commit Repeatable read, 保证读取最新的 commit, 为此, 读取的时候不容许提交 Serializable, 要求有很高的实时同步性 # 这四个级别能够逐个解决脏读 、不可重复读 、幻读 这几类问题
数据结构, 对数据的操做, 完整性约束
Create, Read, Update, and Delete
过程
1.首先链接到数据库 conn = sqlite.connect('test.db') 2.创建游标 cursor cursor = conn.cursor() 3.创建表 create table user (id int, name varchar(20), score int ) 4.insert into 插入数据, 注意占位符是 ? insert into user (id, name) values(1, "Alice", 88) insert into user (id, name) values(2, "Bob", 89) insert into user (id, name) values(3, "Cindy", 88) 5.select * from user where 查找数据 select * from user where id between 1 and 3 order by score asc 6.cursor.close() 7.conn.commit() 8.conn.close()
column, 列, 字段
select * from user select col1, col2 from user
下面以这个表格 customers
为例, 展现 SQL 的语法
id | name | age | city | postalcode | country |
1 | Alfreds | 25 | Berlin | 12209 | Germany |
2 | Ana | 15 | Mexico | 05021 | Mexico |
3 | Antonio | 20 | Mexico | 05023 | Mexico |
4 | Thomas | 30 | London | WA11DP | UK |
5 | Berglunds | 35 | Lulea | S-958-22 | Sweden |
where 条件选择
select * from customers where country='Germany' and city='Berlin'
order by 排序
select * from customers order by country
插入
insert into customers (name, age, city, postalcode, country) values ('Bart', 10, 'LA', '4006', 'USA')
更新
update customers set name = 'Smith', city = 'Paris' where id = 5
删除
delete from customers where name = 'Berglunds'
limit/top 不返回所有结果, 只返回有限数量的记录
# SQL select top 3 from customers # MySQL select * from customers limit 3
最大最小值
select min(age) from customers
统计 count, distinct
# 统计有多少个不一样的国家 select count(distinct country) from customers
平均值
select avg(age) from customers
求和
select sum(age) from customers
通配符
# SQL select * from customers where name like 'B%' # sqlite select * from customers where name like 'B*'
选择范围
# 离散 select * from customers where country in ('Germany', 'France') # 连续 select * from customers where age between 10 and 20
链接表格
inner join, (A ∩ B) left join, (A ∩ B) U A right join, (A ∩ B) U B full outer join, (A U B)
2xx: Successful responses
3xx: Redirection messages
This response code means that the URI of the requested resource has been changed permanently. Probably, the new URI would be given in the response.
4xx: Client error responses
This response means that server could not understand the request due to invalid syntax.
The client does not have access rights to the content, i.e. they are unauthorized, so server is rejecting to give proper response. Unlike 401, the client's identity is known to the server.
The server can not find requested resource. In the browser, this means the URL is not recognized. In an API, this can also mean that the endpoint is valid but the resource itself does not exist. Servers may also send this response instead of 403 to hide the existence of a resource from an unauthorized client. This response code is probably the most famous one due to its frequent occurence on the web.
The request method is known by the server but has been disabled and cannot be used. For example, an API may forbid DELETE-ing a resource. The two mandatory methods, GET and HEAD, must never be disabled and should not return this error code.
5xx: Server error responses
The server has encountered a situation it doesn't know how to handle.
The request method is not supported by the server and cannot be handled. The only methods that servers are required to support (and therefore that must not return this code) are GET and HEAD.
https://developer.mozilla.org...
GET为请求数据, 没有反作用, 每次请求的效果都相同。
POST为修改数据, 相对GET来说没有那么安全(由于要修改数据)。
GET 经过 URL 传输数据, 容易在日志记录中留下私密数据, 隐蔽性没有POST好。
通常经过GET方式传输数据, 因为Web Server和浏览器限制, URL长度限制传输的数据有限(根据Web Server配置和浏览器不一样, 通常为2kB~8kB)
而POST一般能够忽略限制(实际上根据Web Server配置也仍是有限制的, 通常是2G)
http://stackoverflow.com/ques...
过程
<br>
B
在第一次收到 A
的 SYN
以后, 没有马上进入 ESTABLISHED
, 而是等到 A
再来一次 ACK
才创建链接, 为何要这样设计?答:防止已经失效的链接请求(好比在某个网络滞留了好久), 忽然又传到了 B
, 从而产生错误, 形成 B
的资源浪费.
考虑这样一种状况: A
的第一次 SYN
被拦截了。而后 A
又发了一次 SYN
, B
收到, 而且完成后续的 握手 --- 数据传输 --- 挥手
。
此时 A
的第一次 SYN
又被放了出来, 并传到 B
, 若是只须要 2
次握手, 那么此时 B
就会直接进入 ESTABLISHED
而这个时候 A
都已经关机了, 不会发数据过来了, B
就在 ESTABLISHED
中苦苦等待 A
, 浪费不少资源。
若是是3次握手, 那么 B
只会进入 SYN-RCVD
状态, 一段时间后 (比 ESTABLISHED
要短, 并且不会占用那么多资源), 会自动取消链接
SYN Flood
是一种广为人知的 DoS
(拒绝服务攻击) , 是 DDoS
(分布式拒绝服务攻击) 的方式之一, 这是一种利用 TCP
协议缺陷, 发送大量伪造的 TCP
链接请求, 从而使得被攻击方资源耗尽 (CPU
满负荷或内存不足) 的攻击方式。
假设一个用户向服务器发送了 SYN
报文后忽然死机或掉线, 那么服务器在发出 SYN+ACK
应答报文后是没法收到客户端的 ACK
报文的 (第三次握手没法完成) ,
这种状况下服务器端通常会重试 (再次发送 SYN+ACK
给客户端) 并等待一段时间后丢弃这个未完成的链接, 这段时间的长度咱们称为 SYN Timeout
, 通常来讲这个时间是分钟的数量级 (大约为30秒 - 2分钟).
一个用户出现异常致使服务器的一个线程等待1分钟并非什么很大的问题, 可是, 若是有一个恶意的攻击者大量模拟伪造这种状况, 服务器端将会维护一个很是大的半链接列表, 从而消耗很是多的资源
数以万计的半链接, 即便是简单的保存并遍历也会消耗很是多的 CPU
时间和内存, 况且还要不断对这个列表中的 IP
进行 SYN+ACK
的重试
实际上若是服务器的 TCP/IP
栈不够强大, 最后的结果每每是堆栈溢出崩溃,
即便服务器端的系统足够强大, 服务器端也将忙于处理攻击者伪造的 TCP
链接请求而无暇理睬客户的正常请求 (毕竟客户端的正常请求比率很是之小) , 此时从正常客户的角度看来, 服务器失去响应, 没法对正常客户进行服务
这就是 SYN Flood
攻击
防护措施: 缩短 SYN Timeout
, 增长 IP
黑名单, 使用 CDN
A
发出的最后一个 ACK
可能会丢失. 而此时 B
还在等待这个 ACK
, 若是 B
一直没有收到, 则会给 A
发一个 FIN + ACK
, 通知 A
刚才那个没收到, 从 A
发出 ACK
到 B
发出 FIN + ACK
须要 2MSL
, 若是 2MSL
时间里面 A
都没有收到 B
的回复, 就认为本身的 ACK
已经送达 B
, 因此 A
能够安心关闭了
并且, 2MSL
后, 可使本次链接所产生的全部报文段都从网络上消失 (TTL, Time To Live
), 之后创建新的链接, 就不会和旧的链接混淆
Intent
交互图
http://www.ruanyifeng.com/blo...
1). Client 给出协议版本号、一个的随机数(Client random),以及客户端支持的加密方法。 2). Server 确认双方使用的加密方法,并给出数字证书,以及一个服务器生成的随机数 3). Client 确认数字证书有效,而后生成一个新的随机数(Premaster secret), 并使用数字证书中的公钥,加密 Premaster secret, 发给 Server 4). Server 使用本身的私钥,获取爱丽丝发来的随机数 Premaster secret 5). Client 和 Server 根据约定的加密方法,使用前面的三个随机数,生成"对话密钥"(session key),用来加密接下来的整个对话过程。 生成对话密钥一共须要三个随机数。 握手以后的对话使用"对话密钥"加密(对称加密),服务器的公钥和私钥只用于加密和解密"对话密钥"(非对称加密),无其余做用。 服务器公钥放在服务器的数字证书之中。
最重要的缘由在于吊销。当网站的私钥丢失时,网站应该向证书颁发机构(CA)申请将他们的证书加入到证书吊销列表(CRL)里。当用户访问https站点时,浏览器会自动向CA请求吊销列表,若是用户访问的站点提供的证书在CRL里,浏览器就不信任这个证书,由于攻击者可能拥有一样的证书。因此若是证书永久有效,随着愈来愈多的私钥丢失,吊销列表也愈来愈大(由于只有加进去的,没有剔出去的),这既给CA增长流量压力,也会增长浏览器的流量。而一旦有效期只有几年,那么CA就能够将那些已通过期了的证书从CRL里剔除,由于反正浏览器也不信任过时证书。
https://segmentfault.com/a/11...
客户端和服务器之间用于传输HTTP数据的TCP链接不会关闭, 若是客户端再次访问这个服务器上的网页, 会继续使用这一条已经创建的链接
javascript, setTimeout() 的用法
console.log(1) for( let i = 0; i < 5; i++ ){ setTimeout(function(){console.log(2);}, 1000); } console.log(3);
输出是什么(1 3 2 2 2 2 2)
异步, 不会等
https://www.liaoxuefeng.com/w...
axios, jQuery, AJAX 是怎么写的
体系结构, 操做系统, 网络, 语言, 数据结构算法, 框架, 应用
若是要作 Java 就专攻 Java, SSM/SSH 实践好, 理解好