• python实现的websocket总结 —— wspy


    之前曾有php版的websocket封装包。见Websocket——php实战,近期使用python做一些功能,须要用到对websocket的操作,因此,參照之前的实现,实现了这个python版本号。

    源代码见https://github.com/OshynSong/wspy


    总体实现起来,须要在建立socket监听port。这须要用到socket标准库模块。之后。须要对对网络字节流进行操作,这个方面python有struct标准库模块。这个很好用;另外涉及到加密解密操作,还有hashlib模块和sha模块等使用。特别在此总结一下。目的主要是
    1 备忘
    2. 总结与思考

    1 socket 操作

    1 本地Socket建立

    建立TCPserver的一般流程:

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind((addr,port))
    sock.listen(10)

    建立好本地socket,并绑定地址与port进行监听。

    2 并发连接策略

    之后,须要使用不同的策略处理多个client连接的问题,最普通的处理方式就是直接使用accept堵塞,这样server端每次仅仅能处理一个client连接。然后python标准库提供了select模块,里面有select、poll和epoll这些不同的并发连接的处理策略。当中poll和epoll仅仅能在linux下使用,并且epoll在linux 2.6之后的版本号才干使用。当然并发处理效果来看。epoll比poll性能更好。poll比select性能更优。

    可是select确能够在多种平台下使用,为了兼容Windows系统。本次实现中使用的是select策略,详细例如以下:

    ... #接上述socket建立代码
    while True:
        rs, ws, es = select.select([sock], [], [])
        for r in rs:
            if r is sock: #r 是server端socket
                cliSock,addr = r.accept()
                r.connect(cliSock) #建立于client连接
            else:
                try:
                    data = r.recv(bufferLen)
                    ... #处理client连接发送的数据
         ...

    poll方法也是select模块内的方法。使用起来比select更简单。首先使用poll建立一个poll对象,然后使用它的register方法注冊一个文件描写叙述符,unregister方法能够移除注冊对象。之后能够调用poll方法得到(fd,event)格式的列表,fd是文件描写叙述符。event代表发生的事件。

    event是一个位掩码。能够使用select模块的常量进行按位操作。
    select模块中polling事件常量:

    事件名 描写叙述
    POLLIN 读取来自文件描写叙述符的数据
    POLLPRI 读取来自文件描写叙述符的紧急数据
    POLLOUT 文件描写叙述符的数据已准备好。可无堵塞写入
    POLLERR 与文件描写叙述符有关的错误情况
    POLLHUP 挂起,连接丢失
    POLLNVAL 无效请求,连接没有打开

    以下是使用poll策略的演示样例代码:

    ... #接上述socket建立代码
    fdmap = {sock.fileno() : s}
    p = select.poll()
    p.register(sock)
    while True:
        events = p.poll()
        for fd,event in events:
            if fd in fdmap:  #本地socket
                c,addr = sock.accept()
                print 'Connected from ', addr
                p.register(c)
                fdmap[c.fileno()] = c
            elif event & select.POLLIN:
                data = fdmap[fd].recv(buffer)
                ...#数据操作
            elif event & select.POLLERR: #断开连接
                p.unregister(fd)
                del fdmap[fd]
       ......

    2 Struct处理字节数据

    这个标准库模块就是用来转换python的数据值与C风格的数据类型的交互,特别是二进制文件和网络的字节数据。基本的方法:

    struct.pack(fmt, v1, v2…)
    struct.pack_into(fmt, buffer, offset, v1, v2…) (将v1,v2等值依照fmt格式pack到buffer字符串以offset開始的之后的位置)
    struct.unpack(fmt, string)
    struct.unpack_from(fmt, buffer [, offset=0])
    struct.calcsize(fmt) (计算fmt的长度)

    上面主要是直接使用struct模块的方法,每一个fmt都须要单独进行。假设须要重用。能够使用struct提供的Struct类。使用fmt实例化Struct对象之后,调用相似方法就能够进行重用。并且这样使用对象调用的性能更好,比直接使用上述方法调用效率更高。

    pack(v1,v2…)
    pack_into(buffer, offset, v1, v2 …)
    unpack(string)
    unpack_from(buffer, offset=0)
    format : 返回实例化Struct对象使用的fmt字符串
    size:返回fmt字符串的长度

    当中最关键的format字符串的使用。
    首先是字节顺序:

    Character Byte order Size Alignment
    @ native native native
    = native standard none
    < little-endian standard none
    > big-endian standard none
    ! network (= big-endian) standard none

    然后就是format使用特殊字符,见下表:

    Format C Type Python type Standard size
    x pad byte no value
    c char string of length 1 1
    b signed char integer 1
    B unsigned char integer 1
    ? _Bool bool 1
    h short integer 2
    H unsigned short integer 2
    i int integer 4
    I unsigned int integer 4
    l long integer 4
    L unsigned long integer 4
    q long long integer 8
    Q unsigned long long integer 8
    f float float 4
    d double float 8
    s char[] string
    p char[] string
    P void * integer

    3 加密解密处理

    hashlib标准库模块提供了经常使用的全部加密解密hash方法。使用到的有:

    hashlib.update(arg):将hash对象使用arg字符串更新。多次调用相当于将全部arg字符串连接到一起
    hashlib.digest() : 返回传如到update方法的字符串的hash值
    hashlib.hexdigest():返回hash值的十六进制字符串表示
    hashlib.copy():返回一个hash值的副本

    websocket中在握手阶段须要获取到client的key,然后使用sha1和base64进行加密处理后发送到client进行握手。

        sha1Encrypt = sha1(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11').digest()
        acceptKey = base64.b64encode(sha1Encrypt)

    总体来说,使用python实现这些操作很方便。与php相比更加简洁。彰显了python语言简洁的本质!

  • 相关阅读:
    SQL查询
    redis 命令行常用命令
    linux ss ip
    jdk下载地址
    requests.session保持会话
    Python通过重写sys.stdout将控制台日志重定向到文件
    解决Python3 控制台输出InsecureRequestWarning问题
    uniapp实现iframe效果
    模拟登录 react 的页面
    vueX的五大属性和使用方法包括辅助函数
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/7216291.html
Copyright © 2020-2023  润新知