51dev.com IT技术开发者社区

51dev.com 技术开发者社区

s21day30 python笔记

Pythonphp学习阅读(18)2019-05-15 收藏0次评论

python笔记">s21day30 python笔记

一、内容回顾及补充

  1. 简述三次握手和四次挥手
    • 三次握手
      • accept接受过程中等待客户端的连接
      • connect客户端发起一个syn链接请求
        • 如果得到了server端响应ack的同时还会再收到一个由server端发来的syc链接请求
        • client端进行回复ack之后,就建立起了一个tcp协议的链接
      • 三次握手的过程再代码中是由accept和connect共同完成的,具体的细节再socket中没有体现出来
    • 四次挥手
      • server和client端对应的在代码中都有close方法
      • 每一端发起的close操作都是一次fin的断开请求,得到'断开确认ack'之后,就可以结束一端的数据发送
      • 如果两端都发起close,那么就是两次请求和两次回复,一共是四次操作
      • 可以结束两端的数据发送,表示链接断开了
  2. tcp协议和udp协议的特点
    • tcp协议:是一个面向连接的,流式的,可靠的,慢的,全双工通信
      • 邮件 文件 http web
    • udp协议:是一个面向数据报的,无连接的,不可靠,快的,能完成一对一、一对多、多对一、多对多的高效通讯协议
      • 即时聊天工具 视频的在线观看

二、黏包现象

  1. 定义:同时执行多条命令之后,得到的结果很可能只有一部分,在执行其他命令的时候又接收到之前执行的另外一部分结果,这种现象就是黏包
  2. 黏包成因:只有tcp有黏包现象,udp永远不会黏包
    • tcp协议中的数据传递
      • tcp协议的拆包机制
      • 面向流的通信特点
  3. 会发生黏包的两种情况:
    • 情况一 发送方的缓存机制
    • 情况二 接收方的缓存机制
  4. 总结:
    • 黏包现象只发生在tcp协议中
    • 从表面上看,黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点
    • 实际上,主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的
  5. tcp协议的黏包现象
    • 什么是黏包现象
      • 发生在发送端的黏包
        • 由于两个数据的发送时间间隔短+数据的长度小
        • 所以由tcp协议的优化机制将两条信息作为一条信息发送出去了
        • 为了减少tcp协议中的“确认收到”的网络延迟时间
      • 发生再接收端的黏包
        • 由于tcp协议中所传输的数据无边界,所以来不及接收的多条
        • 数据会在接收放的内核的缓存端黏在一起
      • 本质: 接收信息的边界不清晰
    • 解决黏包问题
      • 自定义协议1
        • 首先发送报头,报头长度4个字节,内容是即将发送的报文的字节长度
          • struct模块 pack 能够把所有的数字都固定的转换成4字节
        • 再发送报文
      • 自定义协议2
        • 我们专门用来做文件发送的协议
        • 先发送报头字典的字节长度,再发送字典(字典中包含文件的名字、大小),再发送文件的内容

三、验证客户端的合法性

  • 客户端是提供给 用户用的 —— 登陆验证

    • 你的用户 就能看到你的client源码了,不需要自己写客户端了
  • 客户端是提供给 机器使用的

    # 方式一:
    # server.py
    import os
    import hashlib
    import socket
    def get_md5(secret_key,randseq):
        md5 = hashlib.md5(secret_key)
        md5.update(randseq)
        res = md5.hexdigest()
        return res
    def chat(conn):
        while true:
            msg = conn.recv(1024).decode('utf-8')
            print(msg)
            conn.send(msg.upper().encode('utf-8'))
    sk = socket.socket()
    sk.bind(('127.0.0.1',9000))
    sk.listen()
    secret_key = b'alexsb'
    while true:
        conn,addr = sk.accept()
        randseq = os.urandom(32)
        conn.send(randseq)
        md5code = get_md5(secret_key,randseq)
        ret = conn.recv(32).decode('utf-8')
        print(ret)
        if ret == md5code:
            print('是合法的客户端')
            chat(conn)
        else:
            print('不是合法的客户端')
            conn.close()
    sk.close()
    
    # client.py
    import hashlib
    import socket
    import time
    def get_md5(secret_key,randseq):
        md5 = hashlib.md5(secret_key)
        md5.update(randseq)
        res = md5.hexdigest()
        return res
    def chat(sk):
        while true:
            sk.send(b'hello')
            msg = sk.recv(1024).decode('utf-8')
            print(msg)
            time.sleep(0.5)
    sk = socket.socket()
    sk.connect(('127.0.0.1',9000))
    secret_key = b'alexsb'
    randseq = sk.recv(32)
    md5code = get_md5(secret_key,randseq)
    sk.send(md5code.encode('utf-8'))
    chat(sk)
    sk.close()
    # 方式二:
    # server.py
    import os
    import hmac
    import socket
    def get_hmac(secret_key,randseq):
        h = hmac.new(secret_key,randseq)
        res = h.digest()
        return res
    def chat(conn):
        while true:
            msg = conn.recv(1024).decode('utf-8')
            print(msg)
            conn.send(msg.upper().encode('utf-8'))
    sk = socket.socket()
    sk.bind(('127.0.0.1',9000))
    sk.listen()
    secret_key = b'alexsb'
    while true:
        conn,addr = sk.accept()
        randseq = os.urandom(32)
        conn.send(randseq)
        hmaccode = get_hmac(secret_key,randseq)
        ret = conn.recv(16)
        print(ret)
        if ret == hmaccode:
            print('是合法的客户端')
            chat(conn)
        else:
            print('不是合法的客户端')
            conn.close()
    sk.close()
    
    # client.py
    import socket
    import time
    import hmac
    def get_hmac(secret_key,randseq):
        h = hmac.new(secret_key,randseq)
        res = h.digest()
        return res
    def chat(sk):
        while true:
            sk.send(b'hello')
            msg = sk.recv(1024).decode('utf-8')
            print(msg)
            time.sleep(0.5)
    
    sk = socket.socket()
    sk.connect(('127.0.0.1',9000))
    secret_key = b'alexsb'
    randseq = sk.recv(32)
    hmaccode = get_hmac(secret_key,randseq)
    sk.send(hmaccode)
    chat(sk)
    sk.close()

四、直接实现tcp协议可并发

  • socketserver模块 直接实现tcp协议可并发的server端

    # server.py
    import socketserver
    class myserver(socketserver.baserequesthandler):
        def handle(self):  # 自动触发了handle方法,并且self.request == conn
            msg = self.request.recv(1024).decode('utf-8')
            self.request.send('1'.encode('utf-8'))
            msg = self.request.recv(1024).decode('utf-8')
            self.request.send('2'.encode('utf-8'))
            msg = self.request.recv(1024).decode('utf-8')
            self.request.send('3'.encode('utf-8'))
    server = socketserver.threadingtcpserver(('127.0.0.1',9000),myserver)
    server.serve_forever()
    
    # client1.py
    import socket
    sk = socket.socket()
    sk.connect(('127.0.0.1',9000))
    for i in range(3):
        sk.send(b'hello,yuan')
        msg = sk.recv(1024)
        print(msg)
    sk.close()
    
    # client2.py
    import socket
    sk = socket.socket()
    sk.connect(('127.0.0.1',9000))
    for i in range(3):
        sk.send(b'hello,wusir')
        msg = sk.recv(1024)
        print(msg)
    sk.close()

以上就是s21day30 python笔记的全部内容,请多关注【51DEV】IT技术开发者社区。