zoukankan      html  css  js  c++  java
  • 2019.9.9学习内容及随堂笔记

    小结

    随口补充:http协议:应用层,底层基于socket,无状态无连接,版本有1.0,1.1(目前主流) 最新2.0
    上节课回顾:

    1. 加入通信循环,使客户端和服务端可以相互发送数据

    2. 加入连接循环, 可以接收多个客户端的连接请求

    3. 执行ssh命令的小案例subprocess
      -psutil模块,统计机器的内存占用率,硬盘占用率。。。。(有兴趣可以看)

    4. 粘包问题

      tcp协议是流式协议

      tcp协议会把数据量较小,时间间隔较短的数据,一次性发送

      5. 解决粘包问题(代码略)
      

    今日内容:

    基于socket的udp

    ​ 重点:sendto recvfrom

    udp协议的特点:

    ​ 1.可以发空(数据报协议,自带头)

    ​ 2.不需要建连接

    ​ 3.不会粘包

    ​ 4.不可靠(客户端、服务端谁断开都不受影响)
    socketserver的使用(并发)
    -tcp的服务端
    ​ -server=ThreadingTCPServer 对象
    ​ -server.serve_forever()

    ​ -写一个类,类里面重写handler方法,方法内收发数据(实现并发起来了)
    -udp的服务端
    ​ -server=ThreadingUDPServer 对象
    ​ -server.serve_forever
    ​ -写一个类,类里重写handler方法,方法内收发数据(实现并发)
    -self.request(tcp/udp是不一样的)
    -self.client_address 客户端地址

    socketserver源码分析

    -ThreadingTCPServer: init:创建socket,bind,listen

    -server.serve_forever(): 创建线程,建立连接,和处理通信

    上节课回顾

    json模块

    import json
    # 把字典格式转成json格式字符串
    #dic = {"name": "lqz", "xx": False, "yy": None}
    #print(type(dic)) #<class 'dict'>
    #dic = json.dumps(dic)
    # print(dic) #{"name": "lqz", "xx": false, "yy": null} /json字符串
    # print(type(dic)) #<class 'str'>
    
    # 以下不是json字符串,注意,就是普通的字符串类型
    # dic2 = str(dic)
    # print(dic2) # {'name': 'lqz', 'xx': False, 'yy': None}
    # print(type(dic2)) #<class 'str'>
    
    
    '''
    ####### 用法:
    json.dumps()  # 把数据类型转成json字符串
    json.dump()   # 把数据类型转成json字符串,并存到文件中
    
    json.loads()  # 把json格式字符串转成数据类型 (字典、列表等)
    json.load()   # 从文件中把json格式字符串转成数据类型
    '''
    
    
    # 不是json格式字符串转换,直接报错
    # ss = 'falsedddddd'
    # # # json.loads()  # 从python3.6以后,支持bytes格式直接转
    # s = json.loads(ss) # 报错,ss不是json格式字符串
    # print(type(s))
    # print(s)
    
    
    # sss = {"name": "lqz", "xx": False, "yy": None}
    # s = json.dumps(sss) #{"name": "lqz", "xx": false, "yy": null}
    # s = json.loads(sss)
    # print(s)
    
    '''
    import os
    size = os.path.getsize('E:老男孩学习内容与笔记day32作业client.py')
     #获取一个文件里面所有的字节数量
    print(size) # 4140
    '''
    
    服务端
    import socket
    server = socket.socket()
    server.bind(('127.0.0.1',8080))
    server.listen(5)
    while True: # 连接循环
        #一旦有个客户连接成功,会返回两个值,如果没有,会一直卡在这
        print('等待客户端连接: ')
        conn, addr = server.accept()
        print('有个客户端已连接', addr)
    
        while True: # 通信连接
            # 卡在这里,等待客户端来发
            print('等待接收数据:')
            data = conn.recv(1024)
            print(data)
            conn.send(data.upper())
        conn.close()
    server.close()
    
    客户端
    
    import socket
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect(('127.0.0.1', 8080))
    while True:
        msg = input('请输入你要发送的数据:')
        client.send(msg.encode('utf-8'))
        data = client.recv(1024)
        print(data)
    client.close()
    
    服务端——粘包
    import socket
    import os
    import json
    import struct
    
    server = socket.socket()
    server.bind(('127.0.0.1',8080))
    server.listen(5)
    
    
    def download_interface():
        while True:  # 连接循环
            # 一旦有客户连接成功,会返回两个值(conn, addr),如果没有,会卡在这里
            conn, addr = server.accept()
            while True: #通信循环
    
                #1.加个文件头
                #{'size': os.path.getsize(), name:'xxx.py'}
    
                #2.计算一下头的长度
                dic = {'size': os.path.getsize('json模块.py'), 'name': 'xxx.py'}
    
                #3.转成bytes格式, 此处以json模块为例
                dic_s = json.dumps(dic)
                dic_b = bytes(dic_s,encoding='utf-8')
    
                #4.获得长度
                dic_b_len = len(dic_b)
    
                # 通过struct模块 将数据长度打包成固定长度字节
                obj = struct.pack('i', dic_b_len)
    
                # 5.发送四个字节
                conn.send(obj)
    
                # 6.发送头部内容
                conn.send(dic_b)
    
                # 7.直接以+形式打开文件,就不需要转换了  rb模式
                with open('json模块.py', 'rb')as f:
                    #conn.send(f.read()) 不能这样运行,如果文件过大,内存无法负载
                # 注:文件是可以迭代的
                    for line in f:
                        conn.send(line)
            conn.close()
        server.close()
    
    def upload_interface():
        while True:  # 连接循环
            # 一旦有客户连接成功,会返回两个值(conn, addr),如果没有,会卡在这里
            conn, addr = server.accept()
            while True: # 通信循环 (下载)
    
    
                #1.先收4个字节
                head=conn.recv(4)
    
                #2.取出头部的长度
                head_len = struct.unpack('i', head)[0]
    
                #3.接收头部
                head = conn.recv(head_len)
    
                #4.通过json反序列化拿到原字典
                dic = json.loads(head)
    
                #5.拿到字典后取出内容真正的长度,以及文件名
                l = dic['size']
                name = dic['name']
    
                # 准备接收
                count = 0
                data = b''
                with open(name, 'wb')as f:
                    while count < l:
                        if l < 1024:
                            data_temp = conn.recv(l)
                        else:
                            if l - count >= 1024:
                                data_temp = conn.recv(1024)
                                print(data_temp)
                            else:
                                data_temp = conn.recv(l - count)
                        data += data_temp
                        count += len(data_temp)
                    f.write(data)
                print('上传完成')
                conn.send('ok'.encode())
    
    客户端——粘包
    
    import socket
    import struct
    import json
    import os
    
    user_info = {'user': None}
    
    client = socket.socket()
    client.connect(('127.0.0.1', 8080))
    
    
    def register():
        while True:
            print('欢迎来到注册功能')
            if not user_info['user']:
                username = input('username').strip()
                pwd = input('pwd').strip()
                re_pwd = input('pwd')
                if re_pwd == pwd:
                    with open('user_info.test', 'w',encoding='utf-8')as f:
                        f.write(f'{username}:{pwd}')
                        print(f'{username}注册成功')
                        break
                else:
                    print('两次密码不一致')
    
    def login():
        while True:
            print('欢迎来到登录功能:')
            username = input('username:').strip()
            pwd = input('pwd:').strip()
            inp_user_info = f'{username}:{pwd}'
            with open('user_info.test', 'r',encoding='utf-8')as f:
                userinfo = f.read()
                if inp_user_info not in userinfo:
                    print('账户或密码错误')
                    break
                else:
                    print(f'{username}登录成功')
                    user_info['user'] = username
    
    
    
    
    
    
    
    
    def download():
        while True: # 通信循环 (下载)
            msg = input('输入任意键下载:')
    
            #1.先收4个字节
            head=client.recv(4)
    
            #2.取出头部的长度
            head_len = struct.unpack('i', head)[0]
    
            #3.接收头部
            head = client.recv(head_len)
    
            #4.通过json反序列化拿到原字典
            dic = json.loads(head)
    
            #5.拿到字典后取出内容真正的长度,以及文件名
            l = dic['size']
            name = dic['name']
    
            # 准备接收
            count = 0
            data = b''
            with open(name, 'wb')as f:
                while count < l:
                    if l < 1024:
                        data_temp = client.recv(l)
                    else:
                        if l - count >= 1024:
                            data_temp = client.recv(1024)
                            print(data_temp)
                        else:
                            data_temp = client.recv(l - count)
                    data += data_temp
                    count += len(data_temp)
                f.write(data)
            print('接收完成')
        client.close()
    
    
    
    def upload():
        while True: #通信循环 (上传)
            msg = input('输入任意键上传:')
    
            #1.加个文件头
            #{'size': os.path.getsize(), name:'xxx.py'}
    
            #2.计算一下头的长度
            dic = {'size': os.path.getsize('json模块.py'), 'name': 'xxx.py'}
    
            #3.转成bytes格式, 此处以json模块为例
            dic_s = json.dumps(dic)
            dic_b = bytes(dic_s,encoding='utf-8')
    
            #4.获得长度
            dic_b_len = len(dic_b)
    
            # 通过struct模块 将数据长度打包成固定长度字节
            obj = struct.pack('i', dic_b_len)
    
            # 5.发送四个字节
            client.send(obj)
    
            # 6.发送头部内容
            client.send(dic_b)
    
            # 7.直接以+形式打开文件,就不需要转换了  rb模式
            with open('json模块.py', 'rb')as f:
                #conn.send(f.read()) 不能这样运行,如果文件过大,内存无法负载
            # 注:文件是可以迭代的
                for line in f:
                    client.send(line)
            data = client.recv(1024)
            print(data.decode())
        client.close()
    
    
    func_dic = {'1': register,
                '2': login,
                '3': download,
                '4': upload
                }
    
    def run():
        while True:
            print('''
            1. 注册
            2. 登录
            3. 下载
            4. 上传
            q. 退出
            ''')
            choice = input('请选择需要的功能:')
            if choice == 'q':
                break
    
            if choice not in func_dic:
                print('选择不存在')
                continue
            func_dic.get(choice)()
    

    socketserver模块

    socketserver_服务端
    # 使用socketserver 写服务端
    # 导入模块
    
    import socketserver
    
    # 自己定义一个类,必须继承BaseRequestHandler
    class MyTcp(socketserver.BaseRequestHandler):
        # 必须重写 handler 方法
        def handler(self):
            try:
                while True: # 通信循环
                    print(self)
                    # 给客户端回消息
                    # conn 对象就是 request
                    # 接收数据
                    print(self.client_address)
                    data = self.request.recv(1024)
                    print(data)
                    if len(data) == 0:
                        return
                    # 发送数据
                    self.request.send(data.upper())
            except Exception:
                pass
    if __name__ == '__main__':
        # 实例化得到一个tcp链接的对象,Threading意思是说,只要来了请求,它自动的开线程来处理连接跟交互数据
        # 第一个参数是绑定的地址,第二个参数是传一个类
        server = socketserver.ThreadingTCPServer(('127.0.0.1',8089), MyTcp)
        #一直在监听
        # 这么理解:只要来了一个请求,就起一个线程(造一个人,做交互)
        server.serve_forever()
    
    client_客户端
    import socket
    import time
    
    soc = socket.socket()
    
    soc.connect(('127.0.0.1', 8089))
    
    while True:
        soc.send('xxxxxx'.encode('utf-8'))
        data = soc.recv(1024)
        print(data)
    
    

    socketserver模块的udp

    socketserver_服务端
    # 使用socketserver写服务端
    # 导入模块
    import socketserver
    
    #自己定义一个类,必须继承BaseRequestHandler
    class MyTcp(socketserver.BaseRequestHandler):
        def handler(self):
            print(self)
            #数据
            print(self.request[0])
            print(self.request[1])
            print(type(self.request[1]))
            self.request[1].sendto('xxxx'.encode('utf-8'), self.client_address)
            # try:
            #     while True: 通信循环
            #         data = self.request.recvfrom(1024)
            #         print(data)
            # except Exception:
            #     pass
    
    if __name__ == '__main__':
        # 实例化得到一个tcp连接的对象,Threading意思是说,只要来了请求,它自动的开线程来处理连接跟交互数据
        #第一个参数是绑定的地址,第二个参数传一个类
        server = socketserver.ThreadingUDPServer(('127.0.0.1',8081), MyTcp)
        #一直在监听
        server.serve_forever()
    
    client_客户端
    import socket
    #udp
    client = socket.socket(type=socket.SOCK_DGRAM)
    
    client.sendto('lqz'.encode('utf-8'),('127.0.0.1',8080))
    # client.sendto('hello'.encode('utf-8'),('127.0.0.1',8080))
    # client.sendto(''.encode('utf-8'),('127.0.0.1',8080))
    data = client.recvfrom(1024)
    print(data)
    
    client2_服务端
    import socket
    import time
    soc = socket.socket()
    
    soc.connect(('127.0.0.1',8081))
    while True:
        soc.send('yyy'.encode('utf-8'))
        print(soc.recv(1024))
    

    udp协议

    udp_服务端
    # 基本版本
    # import socket
    # # udp
    # server = socket.socket(type=socket.SOCK_DGRAM)
    #
    # server.bind(('127.0.0.1',8080))
    #
    # # udp不要建立连接,直接发
    # #需不需要监听
    # # 跟tcp的是不一样的
    # ##data = server.recvfrom(1024)
    # data,addr = server.recvfrom(1024)
    # ## data是一个元组,一个参数是数据部分,第二个参数是客户地址
    # print(data)
    # server.sendto(data.upper(),addr)
    
    # 加入通信循环
    import socket
    #udp
    server = socket.socket(type=socket.SOCK_DGRAM)
    
    server.bind(('127.0.0.1',8080))
    
    while True:
        data, addr = server.recvfrom(1024)
        print(data)
        server.sendto(data.upper(), addr)
    
    udp_客户端
    # import socket
    # ## udp
    # client = socket.socket(type=socket.SOCK_DGRAM)
    #
    # # 直接发
    # client.sendto(b'lqz',('127.0.0.1', 8080))
    # data = client.recvfrom(1024)
    # print(data)
    
    #加入通信循环
    import socket
    #udp
    client = socket.socket(type=socket.SOCK_DGRAM)
    
    while True:
        msg = input('>>>:')
        #直接发
        client.sendto(msg.encode('utf-8'),('127.0.0.1', 8080))
        data = client.recvfrom(1024)
        print(data)
    

    udp协议是否丢包

    udp_服务端
    # udp 协议没有粘包问题(udp协议又叫数据报协议),可以发空,tcp协议不行
    import socket
    server = socket.socket(type=socket.SOCK_DGRAM)
    server.bind(('127.0.0.1', 8080))
    while True:
        data, addr = server.recvfrom(1024)
        print(data)
        server.sendto(data.upper(), addr)
    
    udp_客户端
    import socket
    
    client = socket.socket(type=socket.SOCK_DGRAM)
    
    while True:
        msg = input('>>>:')
        client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080))
        data = client.recvfrom(1024)
        print(data)  #(b'HELLO', ('127.0.0.1', 8080))
        print(data[0]) #b'HELLO' 通过索引来取出数据内容
        # 注:此处客户端接收“client.recvfrom(1024)”会返回两个值,一个是数据,一个是地址,如果只用一个变量接收,那么会的到一个元组,里面包换数据及服务端ip地址
    
        # data, addr = client.recvfrom(1024)
        # print(data) #'HELLO'
        # print(addr) #('127.0.0.1', 8080)
    
    
    udp_客户端丢包
    import socket
    # udp 不会管客户端或者服务端是否收到,它只管发,所以不可靠
    client = socket.socket(type=socket.SOCK_DGRAM)
    
    while True:
        msg = input('>>>:')
        client.sendto(msg.encode('utf-8'),('127.0.0.1', 8080))
    
        data, addr = client.recvfrom(1024)
        print(data)
    
    
    # udp特点:
    #     可以发空(udp协议是数据报协议,自带头,tcp协议是数据流协议)
    #     客户端和服务端可以有一方没在线(因为不需要建立连接)
    
  • 相关阅读:
    Recommended Books for Algo Trading in 2020
    Market Making is simpler than you think!
    Top Crypto Market Makers of 2020
    Top Crypto Market Makers, Rated and Reviewed
    爬取伯乐在线文章(五)itemloader
    爬取伯乐在线文章(四)将爬取结果保存到MySQL
    爬取伯乐在线文章(三)爬取所有页面的文章
    爬取伯乐在线文章(二)通过xpath提取源文件中需要的内容
    爬取伯乐在线文章(一)
    爬虫去重策略
  • 原文地址:https://www.cnblogs.com/chmily/p/11497874.html
Copyright © 2011-2022 走看看