0%

2020年5月22日 下午3:21

问题总结:

  1. 都 2019 年了,还问 GET 和 POST 的区别
    1. 总结:
      1. GET 用于获取信息,是无副作用的,是幂等的,且可缓存
      2. POST 用于修改服务器上的数据,有副作用,非幂等,不可缓存
    2. 几个错误的传说:
      1. GET 方法参数写法是固定的吗?
      2. POST 方法比 GET 方法安全
      3. GET 方法的长度限制是怎么回事?
      4. POST 方法会产生两个 TCP 数据包?
  2. 什么是队头阻塞?为什么pipelining会操作队头阻塞?
    1. 什么是队头阻塞?
      1. 从名字上就可以看出来:其中的“队”指的是队列。队列有先进先出(FIFO),对应到client端就是:先发出去的,我要先收到返回的相应。
    2. 为什么pipelining会操作队头阻塞?
      1. 管道化要求服务端按照请求发送的顺序返回响应(FIFO),原因很简单,HTTP请求和响应并没有序号标识,无法将乱序的响应与请求关联起来。
        1. 也就是说client端需要知道那个请求被相应了,由于没有需要标识,就只能按顺序来默认了(真是够笨的!)
      2. 客户端需要保持未收到响应的请求,当连接意外中断时,需要重新发送这部分请求。
    3. 管道化是多有的请求都可以是使用的技巧吗?
      1. 只有幂等的请求才能进行管道化,也就是只有GET和HEAD请求才能管道化,否则可能会出现意料之外的结果
      2. 什么是幂等性?
        1. 一个HTTP方法是幂等的,指的是同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也是一样的。
        2. 换句话说就是,幂等方法不应该具有副作用(统计用途除外)
      3. 幂等性只与后端服务器的实际状态有关,而每一次请求接收到的状态码不一定相同
  3. 为什么叫多路复用?它为什么可以解决队头阻塞问题?
    1. 为什么叫多路复用?
      1. 将多个请求复用同一个tcp链接中
    2. 它为什么可以解决队头阻塞问题?
      1. 要回答这个问题,首先我们需要从上面的:为什么pipelining会操作队头阻塞?开始分析
        1. 引起队头阻塞的根本原因是传递消息的没有序号标识
      2. 于是,我们就给每个消息一个序号标识不就行了吗?
        1. 对,并且在http2.0中还进一步的将消息进行的切割,让他的粒度更加的小变成了帧,每个帧都有一个序号,标识他在某个消息中的顺序。
        2. 每个帧在传输是属于一个数据流,而一个连接上可以存在多个流,各个帧在流和连接上独立传输,到达之后在组装成消息,这样就避免了请求/响应阻塞。
      3. 为什么要切分为更小的粒度,帧?
        1. 因为这样就可以让server端,在接受消息的时候可以同时接收到多种消息,即使每个消息只有一部分。
        2. 这样做的好处是类似于消息并发传递的感觉,而不是传完一个消息再传另外一个,由于这样做到了消息的并发传递,那么也实现了队头阻塞中所指的消息为单位阻塞在队列中。

      4. 上面也回答了:如何实现多路复用?
  4. 在使用了帧、流的技巧之后,队头阻塞依然还会发生?
    1. 当我们把多个需要传递的消息切碎,然后通过tcp进行传递给服务端,虽然这是没有了消息这个概念,因为消息切成了帧。但是这里的帧由于是使用tcp进行传递的,tcp本身实现的滑动窗口确认机制依然会造成帧的阻塞。
    2. 这不过这个阻塞是在帧的粒度下,而不是在消息的粒度下。
  5. 什么是队头阻塞以及如何解决_网络_weixin_34364071的博客-CSDN博客

http的发展

【Http】队头阻塞(Head of line blocking)多路复用(Multiplexing) - 是谁扭曲了时空 - 博客园

  • 图中第一种请求方式,就是单次发送request请求,收到response后再进行下一次请求,显示是很低效的。
  • 于是http1.1提出了管线化(pipelining)技术,就是如图中第二中请求方式,一次性发送多个request请求。
    • 而在持久连接的基础上,HTTP1.1进一步地支持在持久连接上使用管道化(pipelining)特性。
    • 管道化允许客户端在已发送的请求收到服务端的响应之前发送下一个请求,借此来减少等待时间提高吞吐;如果多个请求能在同一个TCP分节发送的话,还能提高网络利用率。
    • 但是因为HTTP管道化本身可能会导致队头阻塞的问题,以及一些其他的原因,现代浏览器默认都关闭了管道化。
  • 然而pipelining在接收response返回时,也必须依顺序接收,如果前一个请求遇到了阻塞,后面的请求即使已经处理完毕了,仍然需要等待阻塞的请求处理完毕。这种情况就如图中第三种,第一个请求阻塞后,后面的请求都需要等待,这也就是队头阻塞(Head of line blocking)。
  • 为了解决上述阻塞问题,http2中提出了多路复用(Multiplexing)技术,Multiplexing是通信和计算机网络领域的专业名词。http2中将多个请求复用同一个tcp链接中,将一个TCP连接分为若干个流(Stream),每个流中可以传输若干消息(Message),每个消息由若干最小的二进制帧(Frame)组成。也就是将每个request-response拆分为了细小的二进制帧Frame,这样即使一个请求被阻塞了,也不会影响其他请求,如图中第四种情况所示。

http格式:


2020年5月21日 下午10:59

1.基础语法:

2.容器

1
2
3
4
list(dict1.keys())   list(dict1.values())

for key,value in dict1.items():
print(key,value)

2020年5月21日 下午10:51

1.基础语法:

我的:
class1.html
老师的:
Lesson1.html

2.容器

我的源码:
class2.html
老师源码:
Lesson2.html

3.函数:

自己的:
class3.html
老师的:
Lesson3+%281%29.html

4.面向对象

自己的:
class4.html
老师的:
Lesson4+%281%29.html

5.numpy

class7.html

6.pandas

class8.html

2020年5月21日 下午9:45

娱乐角度讲:

程序的编译与解释有什么区别? - 知乎

专业角度讲:是否生成目标程序

  1. 由解释器根据输入的数据当场执行而不生成任何的目标程序.
  2. 先将源代码编译成目标语言(如:机器语言)之后通过连接程序连接到生成的目标程序进行执行。
  3. 编译执行和解释执行的区别_java_Cobing Liu-CSDN博客

2020年5月20日 上午10:12
进程 vs. 线程 - 廖雪峰的官方网站

  1. 进行的优点-稳定性高:
    1. 多进程模式最大的优点就是稳定性高,因为一个子进程崩溃了,不会影响主进程和其他子进程。
  2. 进程的缺点-开销:
    1. 多进程模式的缺点是创建进程的代价大,在Unix/Linux系统下,用fork调用还行,在Windows下创建进程开销巨大。
    2. 另外,操作系统能同时运行的进程数也是有限的,在内存和CPU的限制下,如果有几千个进程同时运行,操作系统连调度都会成问题
  3. 反之就是线程的缺点

2020年5月20日 下午1:36

  1. 网关本质是什么?
    1. 网关,默认网关,自动网关,路由,网关与路由器的关系
    2. 字面意思:一个子网络的关口。进出一个子网络都需要走这个门
    3. 不是一个协议(http_tcp),不是一段业务代码(子功能模块),不是一个硬件设备(pc_路由器),他是一个特殊的标识,标识一个子网络的关口(叫做网关),其实就是一个ip地址。
    4. 在网络体系中:网关实质上是一个网络通向其他网络的IP地址
      1. 一般来说,路由器的LAN接口的IP地址就是你所在局域网中的网关
      2. 也就是一个在一个子网络中标志门的位置
  2. 如何获取网关的ip?
    1. 设置默认网关:本机设置默认网关
      1. 默认网关必须是电脑自己所在的网段(将IP地址和子网掩码作与运算,得到网段)中的IP地址,而不能填写其他网段中的IP地址
    2. 自动网关:DHCP服务器中设置默认网关
      1. 自动网关设置就是利用DHCP服务器来自动给网络中的电脑分配IP地址、子网掩码和默认网关。这样做的好处是一旦网络的默认网关发生了变化时,只要更改了DHCP服务器中默认网关的设置,那么网络中所有的电脑均获得了新的默认网关的IP地址。这种方法适用于网络规模较大、TCP/IP参数有可能变动的网络
    3. 如何获取网关MAC
      1. 发一个ARP广播到192.168.1.X整个网段,来查找IP是192.168.1.1 的MAC
  3. 什么样的数据包会发给网关?
    1. 为什么不同网段的ip 不能直接通信 - svolcano - 博客园
      1
      2
      3
      4
      5
      if (IP层中,使用子网掩码验证当前数据包的目的主机在本地网络中)直接发往目标ip地址
      else if (数据包地址不在本地网络中) {
      if (设置了默认的网关ip || DHCP服务器发来了网关ip) 发往默认网关ip
      else 数据包到这一步就丢弃了
      }
  4. 如果我们人为的设置一个假的、不存在的网关,会发生什么?
    1. 因为环境里并没有这个网关设备存在.所以A会发一个 ARP广播到192.168.1.X整个网段,来查找IP是192.168.1.1 的MAC,当然,物理上就不存在192.168.1.1这个设备,自然就没有设备来响应这个ARP广播,所以最终IP协议无法知道目的MAC,就无法将数据包往下一个层数据链路层传递.
  5. 网关和路由是什么关系?
    1. 网关是网络中的一个角色/标识,指的是一个“网络”中的出口,
    2. 路由器是一种设备
    3. 路由器可以实现网关的功能,但是路由器功能不仅仅是实现网关
    4. 网关可以由路由器实现,但是也不仅仅是由路由器实现
  6. 路由器的那些功能是网关没有的?
    1. 路由器使用一系列算法决定网络间的最短路径。
      1. 路由器使用静态路由或动态路由来决定网络间的最短路径。静态路由需要管理员手动设置,而动态路由使用一些协议来动态发现网络间的路径并判断最短路径。通常,对于小型网络使用静态路由,大型复杂网络使用动态路由。

2020年5月18日 上午9:54

总结:

  1. 基类的设计思路:
    1. 需要先后站在两个角度:
      1. 为了用户角度:
        1. 我们作为基类,要提供给所有的所有用户基本的功能。继承类中可以添加新的功能,但是基本功能是必须保证的。
      2. 为了继承类的角度:
        1. 我们作为基类,需要为继承类提供哪些通用功能,这些功能时候所有继承类都很有可能用到的,我提供好了,你们这些基类就不用重复再写了。做到代码复用
    2. private :
      1. 我的理解来自与算法题,当我们写一道算法题的时候,我们常常需要把某个核心的子功能封装成一个private方法,这样做的原因是为了避免我们的代码写出来是一坨,让代码第一眼从结构和函数名上看上去更有逻辑,更容易让人看懂。
    3. virtual :在用户直接调用的方法中,找到哪些是可以让子类自定义的
  2. 强制转换的使用场景:
    1. 函数调用过程:
      1. GetSomeNews(string str)
      2. SetChange(string news) —— 发送者
      3. Notify(void* pArg) —— 传递者
      4. Update(void* pArg) ——— 传递者
      5. einterpret_cast<char*>(pArg) —— 接受者

附录:

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include "stdafx.h"

using namespace std;
class News : public Observerable
{
public:
virtual void GetSomeNews(string str)
{
SetChange("News: " + str);
}
};

class User1:public Observer
{
public:
virtual void Update(void* pArg)
{
cout << "User1 Got News: " << reinterpret_cast<char*>(pArg) <<endl;
}
};
class User2 :public Observer
{
public:
virtual void Update(void* pArg)
{
cout << "User2 Got News: " << reinterpret_cast<char*>(pArg) <<endl;
}
};

int main()
{
User1 u1;
User2 u2;

News n1;
n1.GetSomeNews("T0");
cout << n1.GetObseverCount() << endl; // 0

n1.Attach(&u1);
n1.Attach(&u2);
n1.GetSomeNews("T1");
cout << n1.GetObseverCount() << endl; // 2

n1.Detach(&u2);
n1.GetSomeNews("T2");
cout << n1.GetObseverCount() << endl; // 1

n1.DetachAll();
n1.GetSomeNews("T3");
cout << n1.GetObseverCount() << endl; // 0

return 0;
}

Observer.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#pragma once

# ifndef OBSEVER_H_1
# define OBSEVER_H_1
class Observer
{
public:
Observer() { ; }
virtual ~Observer() { ; }

// 当被观察对象发生变化时,通知被观察者调用这个方法
virtual void Update(void* pArg) = 0;
};
# endif

Observerable.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include "stdafx.h"
#include "Observerable.h"


Observerable::Observerable():_bChange(false)
{

}


Observerable::~Observerable()
{
}


// 注册观察者
void Observerable::Attach(Observer* pOb)
{
if (pOb == NULL)
{
return;
}

// 看看当前列表中是否有这个观察者
auto it = _Obs.begin();
for (; it != _Obs.end(); it++)
{
if (*it == pOb)
{
return;
}
}

_Obs.push_back(pOb);
}

// 反注册观察者
void Observerable::Detach(Observer* pOb)
{
if ((pOb == NULL) || (_Obs.empty() == true))
{
return;
}

_Obs.remove(pOb);
}

void Observerable::SetChange(string news)
{
_bChange = true;

Notify( ( (void*)news.c_str() ));
}


void Observerable::Notify(void* pArg)
{
if (_bChange == false)
{
return;
}

// 看看当前列表中是否有这个观察者
auto it = _Obs.begin();
for (; it != _Obs.end(); it++)
{
(*it)->Update(pArg);
}

_bChange = false;
}

Observerable.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#pragma once

#include "Observer.h"
class Observer;

#include <string>
#include <list>
using namespace std;
class Observerable
{
public:
Observerable();
virtual ~Observerable();

// 注册观察者
void Attach(Observer* pOb);
// 反注册观察者
void Detach(Observer* pOb);

int GetObseverCount() const
{
return _Obs.size();
}

void DetachAll()
{
_Obs.clear();
}

virtual void GetSomeNews(string str)
{
SetChange(str);
}
protected:
void SetChange(string news); // 有变化,需要通知

private:
void Notify(void* pArg);

private:
bool _bChange;
list<Observer*> _Obs;
};