zoukankan      html  css  js  c++  java
  • 小知识点记录

    JsonP

    // 利用script的src属性绕过浏览器的同源策略,但是只能发GET请求
    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
    
        <p>
            <input type="button" onclick="Jsonp1();"  value='提交'/>
        </p>
    
        <p>
            <input type="button" onclick="Jsonp2();" value='提交'/>
        </p>
    
        <script type="text/javascript" src="jquery-1.12.4.js"></script>
        <script>
            function Jsonp1(){
                var tag = document.createElement('script');
                tag.src = "http://c2.com:8000/test/";
                document.head.appendChild(tag);
                document.head.removeChild(tag);
    
            }
    
         function list(data){
              console.log(data)
         } 
            function Jsonp2(){
                $.ajax({
                    url: "http://c2.com:8000/test/",
                    type: 'GET',
                    dataType: 'JSONP',
                    jsonp:'callback',       //URL上多出 ?callback=list
                    jsonpCallback:'list',  //返回数据后执行list函数
     //               success: function(data, statusText, xmlHttpRequest){
     //                   console.log(data);      // 没有jsonp,jsonpCallback参数,执行此函数。
                    }
                })
            }
    
        </script>
    </body>
    </html>
    
    //远程:
    //func_name = request.GET.get('callback')
    //return HttpResponse('%s("机密数据")' %func_name)
    

    CORS

    Access-Control-Allow-Origin
    Access-Control-Request-Method
    Access-Control-Request-Headers
    

    乐观锁

    应用于抢票,排号系统
    乐观锁,其实是开发者自己实现的逻辑, 如果更新时的数据库数据和读取时不一样,则等会再重试
    更新失败后,休息一段时间后再进行重试
    

    Python内存管理机制&垃圾回收机制

    两个重要的结构体

    include/object.h

    #define _PyObject_HEAD_EXTRA
        struct _object *_ob_next;  // 双端链表的下一个指针
        struct _object *_ob_prev;  // 双端链表的上一个指针
         
    #define PyObject_HEAD       PyObject ob_base;
     
    #define PyObject_VAR_HEAD      PyVarObject ob_base;
     
     
    typedef struct _object {
        _PyObject_HEAD_EXTRA   // 用于构造双向链表
        Py_ssize_t ob_refcnt;  // 引用计数器
        struct _typeobject *ob_type;    // 数据类型
    } PyObject;
     
     
    typedef struct {
        PyObject ob_base;   // PyObject对象
        Py_ssize_t ob_size; // 元素个数
    } PyVarObject;
    

    以上源码是Python内存管理中的基石,其中包含了:

    • 2个结构体
      • PyO bject,此结构体中包含3个元素。
        • _PyObject_HEAD_EXTRA,用于构造双向链表。
        • ob_refcnt,引用计数器。
        • *ob_type,数据类型。
      • PyVarObject,次结构体中包含4个元素(ob_base中包含3个元素)
        • ob_base,PyObject结构体对象,即:包含PyObject结构体中的三个元素。
        • ob_size,内部元素个数。
    • 3个宏定义
      • PyObject_HEAD,代指PyObject结构体。
      • PyVarObject_HEAD,代指PyVarObject对象。
      • _PyObject_HEAD_EXTRA,代指前后指针,用于构造双向队列。

    Python中所有类型创建对象时,底层都是与PyObject和PyVarObject结构体实现,一般情况下由单个元素组成对象内部会使用PyObject结构体(float)、由多个元素组成的对象内部会使用PyVarObject结构体(str/int/list/dict/tuple/set/自定义类),因为由多个元素组成的话是需要为其维护一个 ob_size(内部元素个数)。

    1. python是由C开发.
    2. include / objects 
    3. 在Python中所有东西创建对象时候,内部都会存储一个数据.
    	// 维护双向链表
        struct _object *_ob_next;        
        struct _object *_ob_prev;
        // 引用计数器
        Py_ssize_t ob_refcnt;
        // 类型
        struct _typeobject *ob_type;
        
        如果是由多个元素组成的话,内部会再多维护一个
        Py_ssize_t ob_size;   // 元素个数
    4. 在创建对象时,如:
       操作:
        	v = 0.3 
       源码内部:
            a. 开辟内存.
            b. 初始化
                ob_fval=0.3
                ob_type=float
                ob_refcnt=1
            c. 将对象加入到双向链表中 ref_chain
       操作:
        	name = v
       源码内部:
        	ob_refcnt+1
            
    	操作:
            del v
        源码内部:
        	ob_refcnt-1
            
        操作:
            def fun(arg):
                print(123)
            fun(name)
    	源码内部:
        	刚进去:ob_refcnt+1
            执行完:ob_refcnt-1
                
    	操作: 
            del name 
    	源码内部:
        	ob_refcnt-1
            每次应用计数器减一时,都会检查是否以为0, 如果是0,则认为他是垃圾,就对他进行回收. 
    
    5. Python内部为了提升效率,会做一些缓存机制.
    
    #define _PyObject_HEAD_EXTRA         
        struct _object *_ob_next;        
        struct _object *_ob_prev;
    
    typedef struct _object {
        // 维护双向链表
        _PyObject_HEAD_EXTRA
        
        // 引用计数器
        Py_ssize_t ob_refcnt;
        // 类型
        struct _typeobject *ob_type;
    } PyObject;
    
    
    typedef struct {
        // 4个: 类型/引用计数器/维护双向链表
        PyObject ob_base; 
        Py_ssize_t ob_size; /* Number of items in variable part */
    } PyVarObject;
    
    #define PyObject_HEAD          PyObject ob_base;
    #define PyObject_VAR_HEAD      PyVarObject ob_base;
    
    使用的类:
    	Pyobject: /float/
    	PyVarObject: list/dict/set/tuple/str/int/bool
    

    内存管理机制

    Python是由C语言开发,操作都是基于底层C语言实现. Python中创建每个对象,内部都会与C语言结构体维护一些值.
    	PyObject
        	上
            下
            计数器
            类型
        PyVarObject
        	PyObject
            容量个数
    在创建对象时,每个对象至少内部有4个值:双向链表/ob_refcnt/ob_type.,之后会对内存中的数据进行初始化,初始化本质: 引用计数器=1,赋值. 然后将对象添加到双向链表中refchain.
    以后再有其他变量执行这个内存,则让引用计数器+1,如果销毁某个变量,则找到指向的内存,将其引用计数器-1.
    引用计数器如果为0,则进行垃圾回收.
    在内部可能存在缓存机制,例如:float/list/int , 最开始不会真正销毁,而是放在free_list的链表中,以后再创建同类型的数据时,会先去链表中取出对象,然后再对对象进行初始化.(float:100/list:80) 
    

    垃圾回收机制

    引用计数器为主,标记清除和分代回收为辅. 
    
    - 引用计数器 (同上)
    - 引用计数器会出现循环引用
    	a = [1,2]
    	b = [5,6]
    	a.append(b) # b的计数器2
    	b.append(a) # a的计数器2
    	
    	del a
    	del b
    	
    - 标记清楚,针对那些容器类的对象,在Python中会将他们单独放到一个双向量表中,做定期扫描,检查是否有循环引用,如果有则各自-1,如果-1之后等于0,则直接回收. 
    
    - 分代回收,为了少扫描对象,将没有问题的对象让他放上上一级链表中,默认下一级扫10次,上一代才扫描1次,总共有3代. 
    

    带参数的装饰器

    from functools import wraps
    
    def auto(arg):
        def wapper(func):
            @wraps(func)  # 不改变被装饰函数的__name__,__doc__等
            def inner(*args, **kwargs):
                print(arg)
                ret = func(*args, **kwargs)
                return ret
            return inner
        return wapper
    
    @auto('怀心抱素')
    def func(arg):
        print(func.__name__)
        return arg
    
    print(func('哈哈'))
    

    显示目录下的所有文件

    import os
    print(list(os.walk('path')))
    

    获取黑窗口的参数

    import sys
    a = sys.argv
    

    上下文管理

    class A:
        def __init__(self, path, mode='r', encoding='utf-8'):
            self.open = open(path, mode=mode, encoding=encoding)
    
        def __enter__(self):
            return self.open
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.open.close()
    
    with A(r'D:python23期	estdjango	emplates	est.html', mode='r') as f1:
        for line in f1:
            print(line)
    

    值类型/引用类型

    值类型:int/str/bool
    引用类型:list/dict/tuple/set(容器类)
    

    构造函数/析构函数

    class Foo:
        __new__
        
        __del__
    

    __new__返回值是什么?

    class Foo:
        def __init__(self,name):
            self.name = name
            
        def __new__(cls,*arg,**kwargs):
        	# 返回的是一个开辟了空间的对象,但是还没有初始化封装属性
            return object.__new__(cls) 
        
        def __del__(self):
            pass
    obj = Foo('alex')
    del obj # 执行析构方法
    

    单例模式

    # 第一种: 线程安全的单例模式
    from threading import Lock
    
    class A:
        __instance = None
        __lock = Lock()
    
        def __init__(self):
            self.name = '单例模式'
    
        def __new__(cls, *args, **kwargs):
            with cls.__lock:
                if not cls.__instance:
                    cls.__instance = object.__new__(cls)
                return cls.__instance
    
    # 第二种: 在一个py文件中实例化类,在其他的py文件中引用,由于加载过的脚本不会再加载,所以也是单例模式
    

    重写

    class Base:
        def f1(self):
            pass
        
    class Foo(Base):
        # 子类重写父类方法
        def f1(self):
            pass
    

    重载(Python中没有)

    # 在C#/JAVA中允许重名方法,只要参数不同即可
    class Base:
        def f1(self):
            pass
        def f1(self,a1):
            print(a1)
    

    接口

    # 第一种: API
    
    # 第二种:Java/C#, 约束实现它的类必须实现指定方法.
    interface IMessage:
    	def f1(self):pass
    接口用interface表关键字修饰,内部可以有方法,方法中不能写代码.
    
    class Foo(IMessage):
    	def f1(self):
    		print(123)
    		
    Foo类"实现"接口IMessage,必须内部实现接口中定义的方法.就像python的类的约束
    

    Python中的约束: 异常+继承

    class Base(object):
    
        def func(self):
            raise NotImplementedError('子类必须实现func方法')
    
    class Foo(Base):
        pass
    
    obj = Foo()
    obj.func() # 软约束,调用方法时才会报错
    

    Python中抽象类 + 抽象方法

    # 很少用
    import abc
    class Base(metaclass=abc.ABCMeta):
    
        @abc.abstractmethod
        def func(self):
            pass
    
        def data(self):
            print(123)
    
    class Foo(Base):
        pass
    
    obj = Foo() # 硬约束,实例化就报错
    

    响应式布局

    # 根据不同的设备,显示不同的样式,做到自适应
    <style>
            #box {
                height: 50px;
                background-color: red;
            }
    
            @media (max- 700px) {
                {# 宽度小于700使用这里的样式 #}
                #box {
                    background-color: yellow;
                }
            }
        </style>
    

    HTTP协议

    超文本传输协议,基于TCP协议,规定了浏览器和服务器的通信格式
    本质是一个规范和约束
    	一次请求&一次响应就断开连接: 短链接/无状态
    	数据格式: 请求行/响应行 请求头/响应头 空行 请求体/响应体
    默认端口: 80
    数据明文传输
    

    HTTPS协议

    安全的数据传输的过程
    需要三个角色: 服务器(公司),客户端(个人),证书管理机构
    1.公司向证书管理机构申请证书(包含公司信息,公钥,签名)和私钥
    2.公司保管私钥
    3.当客户端向服务器发起请求时,服务器将证书发给客户端
    4.客户端会验证证书的有效性(通过签名)
    5.验证通过后,在本地生成一个密钥,使用证书内的公钥对密码进行加密,然后发给服务器
    6.服务器拿到客户端发来的加密数据,使用私钥解密出客户端的密钥
    7.这样客户端和服务器就有了一对对称密钥,然后使用这对密钥进行通讯
    

    轮询

    用一个web聊天室来举例
    前端定时向后端频繁发送请求,询问是否有新的消息
    	- 压力大
    	- 延迟
    	
    <script>
        function getMessage() {
            $.ajax({...})
        }
        setInterval(getMessage,2000)
    </script>
    

    长轮询

    使用队列Queue的阻塞机制,在前端请求数据时,如果没有信息,则让他阻塞一段时间,一有信息马上返回,前端收到响应后,马上再次发送请求
    
    view中:
    from queue import Queue
    from django.http.response import JsonResponse
    
    user_dict = {}
    
    
    def func(request):
        try:
            user = request.GET.get('user')
            message = user_dict[user].get(timeout=30)
            ret = {
                'status': True,
                'data': message
            }
        except Exception:
            ret = {
                'status': False
            }
    
        return JsonResponse(ret)
    
    
    class TestView(View):
        def get(self, request):
            user_name = request.GET.get('user')
            user_dict[user_name] = Queue()
            return render(request, 'test.html', {'user': user_name})
    
        def post(self, request):
            message = request.POST.get('data')
            user = request.POST.get('user')
            print(message)
            print(user)
            for i in user_dict:
                user_dict[i].put(message)
            return HttpResponse('ok')
    
    <script>
        function postMessage() {
            $.ajax({
                url: '/test/',
                type: 'POST',
                data: {
                    "data": $('#data').val(),
                    user: "{{ user }}"
                },
                success: function (res) {
                }
            })
        }
    
        function getMessage() {
            $.ajax({
                url: '/func/',
                type: 'GET',
                data: {
                    user: "{{ user }}"
                },
                success: function (res) {
                    console.log(res);
                    if (res.status) {
                        var p = document.createElement('p');
                        p.innerText = res.data;
                        $('#message').append($(p))
                    }
                    getMessage()
                }
            })
        }
        getMessage()
    </script>
    

    websocket

    实现了web版的socket,浏览器会创建一个socket,并且与服务端创建连接,连接后不断开.
    重点: 魔法字符串magicstring
    原理: 
    1.浏览器发起websocket请求,浏览器生成一个随机的字符串
    2.将随机字符串发给服务端(这次发的是HTTP请求),服务端将魔法字符串和随机字符串(固定的)进行拼接,然后对拼接的结果进行加密(sha265),将加密结果返回给客户端
    3.客户端收到响应,在本地也将魔法字符串和随机字符串进行拼接和加密,然后和响应进行比较,如果比较成功,意味服务端支持websocket,这样就完成了校验服务端是否支持websocket(这个验证过程称为握手环节)
    4.客户端向服务端发送信息(加密的)
    5.服务端收到客户端的加密信息进行解密(统一的)
    	1.取出第二个字节的后7位(即10-16位),最大表示0-127
    	2.对这个值进行判断(当前位置在第二个字符(16位))
    		<= 125 前2个字节是数据头,后面就是数据包
    		== 126 从当前位置再往后读2个字节,后面的是数据包
    		== 127 从当前位置再往后读8个字节,后面的是数据包
    	3.拿到数据包进行解密
    		前四个字节是masking key, 后面的是加密的数据
    		对数据进行解密,一个字节一个字节的解密
    		拿一个字节,第一个是0,和0%4取余,得到的值作为索引,取出masking key的索引对应的字节,和这个字节做与运算,得到一个字节的真正数据,然后读第二个字节,直至完毕,就拿到了全部的解密数据
    
    import socket
    import base64
    import hashlib
    
    def get_headers(data):
        """
        将请求头格式化成字典
        """
        header_dict = {}
        data = str(data, encoding='utf-8')
        header, body = data.split('
    
    ', 1)
        header_list = header.split('
    ')
        for i in range(0, len(header_list)):
            if i == 0:
                if len(header_list[i].split(' ')) == 3:
                    header_dict['method'], header_dict['url'], header_dict['protocol'] = header_list[i].split(' ')
            else:
                k, v = header_list[i].split(':', 1)
                header_dict[k] = v.strip()
        return header_dict
    
    
    def get_real_data(info):
        """
        获取解密数据
        & 与运算
        例如
        11101010
        01111111
        01101010
        """
        payload_len = info[1] & 127
        if payload_len == 126:
            extend_payload_len = info[2:4]
            mask = info[4:8]
            decoded = info[8:]
        elif payload_len == 127:
            extend_payload_len = info[2:10]
            mask = info[10:14]
            decoded = info[14:]
        else:
            extend_payload_len = None
            mask = info[2:6]
            decoded = info[6:]
    
        bytes_list = bytearray()
        for i in range(len(decoded)):
            chunk = decoded[i] ^ mask[i % 4]
            bytes_list.append(chunk)
        body = str(bytes_list, encoding='utf-8')
        return body
    
    
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('127.0.0.1', 8002))
    sock.listen(5)
    # 等待用户连接
    conn, address = sock.accept()
    data = conn.recv(1024)
    headers = get_headers(data)  # 提取请求头信息
    # 对请求头中的sec-websocket-key进行加密
    response_tpl = "HTTP/1.1 101 Switching Protocols
    " 
                   "Upgrade:websocket
    " 
                   "Connection: Upgrade
    " 
                   "Sec-WebSocket-Accept: %s
    " 
                   "WebSocket-Location: ws://%s%s
    
    "
    magic_string = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
    value = headers['Sec-WebSocket-Key'] + magic_string
    ac = base64.b64encode(hashlib.sha1(value.encode('utf-8')).digest())
    response_str = response_tpl % (ac.decode('utf-8'), headers['Host'], headers['url'])
    # 响应【握手】信息
    print(headers['Sec-WebSocket-Key'])
    conn.send(bytes(response_str, encoding='utf-8'))
    while True:
        data = conn.recv(1024)
        print(get_real_data(data))
    

    Django实现websocket

    # 使用channels(官方推荐) python3.6 (3.5和3.7会报错)
    # 内部依赖asgi协议, daphne(支持websocket/http协议)
    
    • channel 实现基本 websocket
    • 给多个人发送消息使用 channel layer
    from channels.generic.websocket import WebsocketConsumer
    from channels.exceptions import StopConsumer
    from asgiref.sync import async_to_sync
    
    
    class ChatConsumer(WebsocketConsumer):
    
        def websocket_connect(self, message):
            """建立连接触发"""
            self.accept()
            async_to_sync(self.channel_layer.group_add)('12312312', self.channel_name)
    
        def websocket_receive(self, message):
            """有消息自动触发"""
            text_data = message['text']
    
            async_to_sync(self.channel_layer.group_send)('12312312', {
                'type': 'xxx.ooo',
                'message': text_data
            })
    
        def xxx_ooo(self, event):
            message = event["message"]
            self.send(message)
    
        def websocket_disconnect(self, message):
            """断开连接触发"""
            async_to_sync(self.channel_layer.group_discard)('12312312', self.channel_name)
            raise StopConsumer()
    
    
    <script>
        function send_message() {
            var data = document.getElementById("txt").value;
            ws.send(data);
        }
    
        var ws = new WebSocket("ws://127.0.0.1:8002/chat/");
        ws.onopen = function (event) {
            // 建立链接成功触发
            var tag = document.createElement('div');
            tag.innerText = "连接成功";
            document.getElementById("message").appendChild(tag);
        };
        ws.onmessage = function (event) {
            // 服务端有消息传来触发
            var tag = document.createElement('div');
            tag.innerText = event.data;
            document.getElementById("message").appendChild(tag);
    
        };
        ws.onclose = function (event) {
            // 服务端主动关闭连接触发
            var tag = document.createElement('div');
            tag.innerText = "关闭连接";
            document.getElementById("message").appendChild(tag);
            ws.close()
        };
    
    </script>
    
  • 相关阅读:
    Overloaded的方法是否可以改变返回值的类型
    parseXXX的用法
    java的类型转换问题。int a = 123456;short b = (short)a;System.out.println(b);为什么结果是-7616?
    UVA 10405 Longest Common Subsequence(简单DP)
    POJ 1001 Exponentiation(大数处理)
    POJ 2318 TOYS(计算几何)(二分)
    POJ 1265 Area (计算几何)(Pick定理)
    POJ 3371 Flesch Reading Ease (模拟题)
    POJ 3687 Labeling Balls(拓扑序列)
    POJ 1094 Sorting It All Out(拓扑序列)
  • 原文地址:https://www.cnblogs.com/zyyhxbs/p/11964335.html
Copyright © 2011-2022 走看看