zoukankan      html  css  js  c++  java
  • 网络编程

    面向对象的使用

    #使用面向对象解决datetime.tody()无法序列化的问题
    
    import json
    from datetime import datetime,date
    
    # print(date.today())         #年月日 2020-12-08
    # print(datetime.today())     #年月日时分秒 2020-12-08 16:07:34.919540
    
    class Myjson (json.JSONEncoder):
        def default(self, o):
            if isinstance(o,datetime):
                return o.strftime('%Y-%m-%d %X')
            elif isinstance(o,date):
                return o.strftime('%Y-%m-%d')
            else:
                return super().default(self,o)
    res = {'c1':datetime.today(),'c2':date.today()}
    print(json.dumps(res,cls=Myjson))
    

    网络编程之 TCP

    #学习网络编程可以开发一个cs架构的软件
    #学习并发、数据库、前端、django可以开发bs架构的软件
    
    #软件开发架构
    	C/S架构(client/server)
        	C:客户端,APP
            S:服务端,架构
        B/S架构(browser/server)
        	B:浏览器,taobao.com/jd.com
            S:服务端
        bs架构实际上也是cs架构
        统一接口:比如微信、支付宝
        
        #服务端
        	24小时不间断提供服务
        #客户端
        	什么时候想体验服务,什么时候去找心仪的服务端寻求服务
            
    #网络编程发展史
    	任何先进的技术基本上都是来源于军事
        #回到过去
        	1.早期的电话				电话线
            2.大屁股电脑				网线
            3.笔记本电脑,无线电话	 网卡
            #要想实现远程通信,第一个需要具备的条件是:物理连接介质
    		人想要实现交流必须统一语言 >>> 英文
            计算机想要与计算机远程通信,除了有物理连接介质之外,还需要有一套公共的标准和协议
            
        #OSI协议
        	OSI七层协议
            	应用层 
                	HTTP协议:超文本传输协议
                    HTTPS协议
                    FTP协议
                表示层
                会话层
                传输层
                	TCP协议/UDP协议,都是基于端口工作的协议
                    	TCP:流式协议、可靠协议(反馈机制),慢,打电话
                            基于TCP协议通信,必须先建立双向通道:TCP协议的三次握手、四次挥手
                                三次握手:
                                    洪水攻击,一台服务器在短时间内接收到了大量的请求
                                四次挥手:
                                    time_wait
                    UDP:数据报协议,不可靠的协议,快,发短信,QQ
                    	无序建立双向通道,数据的传输不安全
                    端口:用来唯一标识计算机上的某个应用程序(0~65535),统常0~1024这些都是操作系统默认使用的端口号,建议手动指定8000以后的端口号(访问端口,输出端口)
                    	mysql	3306
                        redis	6379
                        djando	8000
                        flask	5000
                        tomcat	8080
                    IP+端口:唯一标识接入互联网的一台计算机上的某个应用程序
                    域名解析:URL DNS
                网络层
                	IP协议,规定了只要是接入互联网的计算机都必须有一个IP地址(公网、私网)
                    IP地址的特点:点分十进制(0.0.0.0 255.255.255.255)
                    IP地址目前有两个版本:IPV4、IPV6
                    路由器:实现局域网与局域网之间的互连
                    交换机:功能强大的路由器,让连接了交换机的计算机,实现彼此之间的互连
                    局域网:是构成互联网的基本单位
                数据链路层
                	1.规定电信号的分组方式
                    2.规定了任何一台接入互联网的计算机,都必须有一块网卡,该网卡上有世界上独一无二的编号(mac地址),该编号由12位16进制数组成(前六位是厂商编号,后六位是流水线编号)
                    #1、2统称为以太网协议(通信基本靠吼)(局域网内使用)
                    	1.广播风暴(广播、单播)
                    #ARP协议:根据ip地址,获取Mac地址,本地缓存
                物理连接层 
                	基于电信号,传输0100010001这样的二进制数据
            
            OSI五层协议
            	应用层
                传输层
                网络层
                数据链路层
                物理连接层
                
    #应用程序所需要的的数据,都是跟程序所在的那台计算机的内存去要
    #TCP协议之所以可靠的原因在于反馈机制
    	反馈机制:计算机每次发数据的时候,必须等到对方的才会将内存中的数据清除,否则会在一定的时间内,每隔一段时间发送一次
    

    socket(套接字)

    Ji

    #server
    import socket
    server = socket.socket()            #不传参数,默认使用的就是TCP协议,买手机
    server.bind(('127.0.0.1',8080))      #bind内为元组,127.0.0.1,为本地回环地址,插电话卡
    server.listen(5)                    #半连接池,开机
    conn,addr = server.accept()         #接听电话,一直等待(阻塞)
    data = conn.recv(1024)              #听别人说话,接收1024个字节,阻塞
    print(data)
    conn.send(b'hello baby')            #给别人回话
    conn.close()                        #挂电话
    server.close()                      #关机
    
    #client
    import socket
    client = socket.socket()                    #拿电话
    client.connect(('127.0.0.1',8080))          #拨号,写对方的ip和端口
    client.send(b'hello world')                 #对别人说话
    data = client.recv(1024)                    #听别人说话,阻塞
    print(data)
    client.close()                              #挂电话
    
    #send()与recv()不要出现两边相同的情况
    #recv()是跟内存要数据,至于数据的来源,recv不管
    

    循环通信

    #server
    import socket
    server = socket.socket()            #生成一个对象
    server.bind(('127.0.0.1',8080))      #绑定ip和端口
    server.listen(5)                    #半连接池
    conn,addr = server.accept()         #阻塞
    while True:
        data = conn.recv(1024)              #听别人说话,接收1024个字节
        print(data)
        conn.send(data.upper())            #给别人回话
    
    # conn.close()                        #挂电话
    # server.close()                      #关机
    
    #client
    import socket
    client = socket.socket()                    #生成一个对象
    client.connect(('127.0.0.1',8080))
    while True:
        msg = input('请输入要发送的内容>>>: ').encode('utf-8')
        client.send(msg)                            #对别人说话
        data = client.recv(1024)                    #听别人说话
        print(data)
    
    # client.close()
    

    socket通信的一些问题

    #server
    import socket
    server = socket.socket()            #生成一个对象
    server.bind(('127.0.0.1',8080))      #绑定ip和端口
    server.listen(5)                    #半连接池
    conn,addr = server.accept()         #阻塞,addr就是客户端的地址
    while True:
        try:
            data = conn.recv(1024)              #conn()类似于双向通道
            print(data)                         #Mac和linux客户端异常退出之后,服务端不会报错,会一致接收b''
            if len(data) == 0:break
            conn.send(data.upper())            #给别人回话
        except ConnectionResetError as e:
            print(e)
            break
    conn.close()                        #挂电话
    server.close()                      #关机
    
    #client
    import socket
    client = socket.socket()                    #生成一个对象
    client.connect(('127.0.0.1',8080))
    while True:
        msg = input('请输入要发送的内容>>>: ').encode('utf-8')
        if len(msg) == 0:continue               #解决客户端输入空,resc()同时出现的情况
        client.send(msg)                            #对别人说话
        data = client.recv(1024)                    #听别人说话
        print(data)
    
    # client.close()
    

    连接循环

    #服务端
    	固定的ip和端口
        24小时不间断提供服务
        
    #server
    import socket
    server = socket.socket()            #生成一个对象
    server.bind(('127.0.0.1',8080))      #绑定ip和端口
    server.listen(5)                    #半连接池,允许最大的等待数(连接数为6)
    while True:
        conn,addr = server.accept()         #阻塞,addr就是客户端的地址
        while True:
            try:
                data = conn.recv(1024)              #conn()类似于双向通道
                print(data)                         #Mac和linux客户端异常退出之后,服务端不会报错,会一致接收b''
                if len(data) == 0:break
                conn.send(data.upper())            #给别人回话
            except ConnectionResetError as e:
                print(e)
                break
        conn.close()                        #挂电话
    # server.close()                      #关机
    
    #client
    import socket
    client = socket.socket()                    #生成一个对象
    client.connect(('127.0.0.1',8080))
    while True:
        msg = input('请输入要发送的内容>>>: ').encode('utf-8')
        if len(msg) == 0:continue               #解决客户端输入空,resc()同时出现的情况
        client.send(msg)                            #对别人说话
        data = client.recv(1024)                    #听别人说话
        print(data)
    # client.close()
    

    模拟终端

    #subprocess模块
    import subprocess
    while True:
        cmd = input('请输入您的命令>>>: ')
        obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
        print(obj.stdout.read().decode('gbk'))        #正确命令返回结果,windows默认使用gbk编码
        print(obj.stderr.read().decode('gbk'))        #错误命令返回结果
    

    TCP协议的粘包问题

    #TCP协议的特点
    	会将数据量比较小的,并且时间间隔比较短的数据一次性打包发给对方
    
    #server
    import socket
    server = socket.socket()
    server.bind(('127.0.0.1',8080))
    server.listen(5)
    conn,addr = server.accept()
    data = conn.recv(5)
    print(data)
    data = conn.recv(5)
    print(data)
    data = conn.recv(4)
    print(data)
    conn.send(b'hello baby')
    conn.close()
    server.close()
    
    #client
    import socket
    client = socket.socket()
    client.connect(('127.0.0.1',8080))
    client.send(b'hello')
    client.send(b'world')
    client.send(b'baby')
    data = client.recv(8)
    print(data)
    client.close() 
    
    #少的数据量将会一次打包发送给服务端,节省资源
    #如果知道数据的发送方发送的字节数,那么双方的信息就可以不用在担心'字节长度问题'
    

    struct模块

    #struct模块
    	可以将任意字符串打包成字节长度为4的包,解包后仍可以得到原来字符串的长度
        当原始数据特别大的时候,i模式装不下了,这个时候就需要更换模式
    
    import struct
    str = 'evfreatteg.t.g..t;hyh;y;5;yjjjjjn'
    print('原始的: ',len(str))
    str1 = struct.pack('i',len(str))        #将数据打包
    print(len(str1))                        #包长度固定位4
    str2 = struct.unpack('i',str1)[0]       #将数据解包
    print('解包后的: ',str2)
    
    原始的:  33
    4
    解包后的:  33
    

    使用struct模块解决粘包问题

    #解决粘包问题 
    	服务端:
        	1.先制作一个要发送给客户端的字典
            2.制作字典的报头
            3.发送字典的报头
            4.发送字典
            5.再发送真实数据长度
        客户端:
        	1.先接受字典的报头
            2.解析拿到字典的数据长度
    		3.接收字典
            4.从字典中获取真实数据长度
            5.接收真实数据
            
    #server
    import socket
    import subprocess
    import struct
    import json
    server = socket.socket()
    server.bind(('127.0.0.1',8080))
    server.listen(5)
    while True:
        conn,addr = server.accept()
        while True:
            try:
                cmd = conn.recv(1024)
                if len(cmd) == 0:break
                cmd = cmd.decode('utf-8')
                obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
                res = obj.stdout.read() + obj.stderr.read()
                d = {'name':'syy','file_size':len(res),'info':'大家为我骄傲'}
                json_d = json.dumps(d)
                #1.先制作一个字典的报头
                header = struct.pack('i',len(json_d))
                #2.发送字典报头
                conn.send(header)
                #3.发送字典
                conn.send(json_d.encode('utf-8'))
                #4.再发送真实数据
                conn.send(res)
                # conn.send(obj.stdout.read())  #只能read()一次
                # conn.send(obj.stderr.read())
            except ConnectionResetError as e:
                print(e)
                break
        conn.close()
    # server.close()                      #关机
    
    #client
    import socket
    import struct
    import json
    client = socket.socket()                    #生成一个对象
    client.connect(('127.0.0.1',8080))
    while True:
        msg = input('请输入要发送的内容>>>: ').encode('utf-8')
        if len(msg) == 0:continue               #解决客户端输入空,resc()同时出现的情况
        client.send(msg)                            #对别人说话
        #1.先接收字典报头
        header_dict = client.recv(4)
        #2.解析报头,获取字典长度
        dict_size = struct.unpack('i',header_dict)[0]
        #3.循环接收字典数据
        dict_bytes = client.recv(dict_size)
        dict_json = json.loads(dict_bytes.decode('utf-8'))
        #4.从字典中获取信息
        print(dict_json)
        recv_size = 0
        real_data = b''
        while recv_size < dict_json.get('file_size'):
            data = client.recv(1024)
            real_data += data
            recv_size += len(data)
        print(real_data.decode('gbk'))
    # client.close()
    

    练习

    #习题
    	写一个上传电影的功能
        	1.循环打印某一个文件夹下面的所有的文件
            2.用户想要上传的文件
            3.将用户选择的文件上传到服务器
            4.服务端保存该文件
            
    #server
    import socket
    import subprocess
    import struct
    import json
    server = socket.socket()
    server.bind(('127.0.0.1',8080))
    server.listen(5)
    while True:
        conn,addr = server.accept()
        while True:
            try:
                header_len = conn.recv(4)
                #解析字典报头
                header_len = struct.unpack('i',header_len)[0]
                #在接收字典数据
                header_dic = conn.recv(header_len)
                real_dic = json.loads(header_dic.decode('utf-8'))
                #获取真实数据长度
                total_size = real_dic.get('file_size')
                #循环接收并写入文件
                recv_size = 0
                with open(real_dic.get('file_name'),'wb') as f:
                    while recv_size < total_size:
                        data = conn.recv(1024)
                        f.write(data)
                        recv_size += len(data)
                    print('上传成功')
            except ConnectionResetError as e:
                print(e)
                break
        conn.close()
    # server.close()                      #关机
    
    #client
    import socket
    import struct
    import json
    import os
    client = socket.socket()                    #生成一个对象
    client.connect(('127.0.0.1',8080))
    while True:
        #获取电影列表,循环展示
        MOVIE_DIR = r'D:python视频day29视频'
        movie_list = os.listdir(MOVIE_DIR)
        for i,movie in enumerate(movie_list,1):
            print(i,movie)
        #用户选择
        choise = input('请输入电影序号>>>: ').strip()
        #判断是否是数字字符串
        if choise.isdigit():
            choise = int(choise)
            #判断用户输入的值的范围是否有效
            if choise in range(1,len(movie_list)+1):
                #获取到用户想要上传的文件名
                path = movie_list[choise-1]
                #拼接文件的绝对路径
                file_path = os.path.join(MOVIE_DIR,path)
                #获取文件大小
                file_size = os.path.getsize(file_path)
                #定义一个字典
                res_d = {
                    'file_name':path,
                    'file_size':file_size,
                    'msg':'尼桑~'
                }
                #序列化字典
                json_d = json.dumps(res_d)
                json_bytes = json_d.encode('utf-8')
                #1.制作字典格式报头
                header = struct.pack('i',len(json_bytes))
                #2.发送字典报头
                client.send(header)
                #3.再发字典
                client.send(json_bytes)
                #4.再发文件数据,打开文件循环发送
                with open(file_path,'rb') as f:
                    for line in f:
                        client.send(line)
        else:
            print('请输入数字序号!')
    

    异常处理

    #什么是异常
    	程序在运行过程中,出现不可预知的错误
        并且该错误没有对应的处理机制,那么就会以异常的形式表现出来
        造成的影响是整个程序无法正常运行
        
    #异常的结构
    	1.异常的类型		NAMEERROP
        2.异常的信息		name 'hhhhhhh' is not defined
        3.异常的位置		File "E:/python_test/a.py", line 6, in <module>
        
    #异常的种类
    	1.语法错误
        	是程序员可以立刻解决的,这种错误是不能容忍的
            
        2.逻辑错误
        	这种错误是可以被容忍的,因为一眼看不出来
            针对逻辑上的错误,可以采用异常处理机制进行捕获
            
    #常见的错误类型
    	1.名字错误		NAMEERROP,变量名、函数名、类名不存在
        2.语法错误		SyntaxError,if/while
        3.键不存在		KeyError
    d = {'name':'syy'}
    print(d['password'])
    	4.值错误		ValueError
    int('ssss')
    	5.索引错误		IndexError
    l = [1,2,3]
    print(l[111])
    	6.关键字assert断言错误  AssertionError
    
    #异常处理
    	在你认为可能会出现bug的代码块上方try一下(try代码块越少越好)
        
    #异常处理的格式
    try:
        想要监控的代码块
    except 错误类型:
        监控到错误类型后自定义的反馈
        
    try:
        想要监控的代码块
    except 错误类型 as e:		#e代表本来代码的错误反馈
        监控到错误类型后自定义的反馈
        
    try:
        想要监控的代码块
    except 错误类型:
        监控到错误类型后自定义的反馈
    else:
        print('被检测的代码没有任何异常发生,才会走else')
    finally:
        print('被检测的代码无论有没有异常发生,都会走finally')
        
    #例
    try:
        name
    except NameError:
        print('NameError已被我处理')
        
        #except可以跟多个
    try:
        # name
        # l = [1,2,3]
        # l[100]
        # d = {'name':'syy'}
        # d['password']
        # if						#语法错误不能被监控
        int('www')
    except NameError:
        print('NameError已被我处理')
    except IndexError:
        print('IndexError已被我处理')
    except KeyError:
        print('KeyError已被我处理')
    except SyntaxError:
        print('SyntaxError已被我处理')
    except ValueError:
        print('ValueError已被我处理')
        
        #万能异常捕获
    try:
        # name
        # l = [1,2,3]
        # l[100]
        # d = {'name':'syy'}
        # d['password']
        # if
        int('www')
    except Exception:				#万能异常捕获,继承自BaseException
        print('所有异常已被我处理')
        
        #else语法
    try:
        # name
        # l = [1,2,3]
        # l[100]
        # d = {'name':'syy'}
        # d['password']
        # if
        int('1')
    except Exception:
        print('所有异常已被我处理')
    else:
        print('被检测的代码没有任何异常发生,才会走else')
    finally:
        print('被检测的代码无论有没有异常发生,都会走finally')
    

    抛出异常

    #关键字raise,就是主动抛出异常
    
    if 'syy' == 'cool':
        pass
    else:
        raise NameError('我觉得不对...')
    

    断言错误

    #关键字assert
    	在关键字assert预言的位置,如果语言对了,代码正常执行,错了的话,报AssertionError错误
    
    l = [1,2,3]
    assert len(l) > 0
    print('断言对了才会走这行代码')
    

    自定义异常

    #主动抛出异常,其实就是将异常类的对象打印出来,会走__str__方法(对象的属性被打印的时候触发)
    
    class MyError(BaseException):
        def __init__(self,msg):
            super().__init__()
            self.msg = msg
        def __str__(self):
            return '<%shhhhhh>' %self.msg
    raise MyError('自定义异常')	
    

    网络编程之 UDP

    UDP通信的基本使用

    #UDP通信
    	数据包协议自带报头
        基于UDP协议的数据传输,数据是不安全的(客户端只发,无论服务端有没有接收)
        
    #server
    import socket
    server = socket.socket(type=socket.SOCK_DGRAM)      #UDP协议
    server.bind(('127.0.0.1',8080))
    #UDP没有半连接池的概念不需要设置半连接池
    #因为没有双向通道,所以不需要accept,直接设置通信循环即可
    while True:
        data,addr = server.recvfrom(1024)
        print('数据',data)        #客户端发来的消息
        print('地址',addr)        #客户端地址
        server.sendto(data.upper(),addr)
        
    #client
    import socket
    client = socket.socket(type=socket.SOCK_DGRAM)
    #不需要建立连接,直接进入通讯循环
    server_address = ('127.0.0.1',8080)
    while True:
        client.sendto(b'hellow',server_address)
        data,addr = client.recvfrom(1024)
        print('服务端发来的数据',data)
        print('服务端的地址',addr)
        
    #UDP类似于发短信,TCP类似于打电话
    

    UDP协议与TCP协议的异同

    #TCP协议
    	1.TCP协议客户端允许为空
        2.TCP协议存在粘包问题
        3.udp协议服务端不存在的情况下,客户端照样会报错
        4.TCP协议不支持并发,使用模块可以做到并发
        
    #UDP协议
    	1.udp协议客户端允许为空?		是的
        2.udp协议不会粘包?	会的
        3.udp协议服务端不存在的情况下,客户端照样不会报错?	会报错,client.recvfrom(1024)报错
        4.udp协议支持并发		是的
        
    #并发:看起来像是同时运行
    #并行:真正意义上的同时运行
    

    基于UDP协议实现简易版的QQ

    #server
    import socket
    server = socket.socket(type=socket.SOCK_DGRAM)      #UDP协议
    server.bind(('127.0.0.1',8080))
    while True:
        data,addr = server.recvfrom(1024)
        print(data.decode('utf-8'))        #客户端发来的消息
        msg = input('请输入你要发送的内容>>>: ').strip()
        server.sendto(msg.encode('utf-8'),addr)
        
    #client
    import socket
    client = socket.socket(type=socket.SOCK_DGRAM)
    server_address = ('127.0.0.1',8080)
    while True:
        msg = input('请输入您要发送的内容(客户端1)>>>: ').strip()
        client.sendto(msg.encode('utf-8'),server_address)
        data,addr = client.recvfrom(1024)
        print(data.decode('utf-8'))
    

    socketserver模块

    模块的简单使用

    #server
    import socketserver
    class MyServer(socketserver.BaseRequestHandler):
        def handle(self):
            print('来了?老弟')
            
    #创建一个基于TCP的对象
    	#只要有客户端连接,会自动交给自定义类中的handler方法去处理
    server = socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyServer)
    #启动该服务的对象
    server.serve_forever()
    
    #client
    import socket
    client = socket.socket()
    client.connect(('127.0.0.1',8080))
    

    socketserver模块使TCP协议支持并发

    #server
    import socketserver
    class MyServer(socketserver.BaseRequestHandler):
        def handle(self):
            # print('来了?老弟')
            while True:
                data = self.request.recv(1024)
                print(self.client_address)      #客户端地址
                print(data.decode('utf-8'))
                self.request.send(data.upper())
    
    #村赶紧啊一个基于TCP的对象
    server = socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyServer)
    #启动该服务的对象
    server.serve_forever()
    
    #client
    import socket
    client = socket.socket()
    client.connect(('127.0.0.1',8080))
    while True:
        client.send(b'hello')
        data = client.recv(1024)
        print(data.decode('utf-8'))
    

    socketserver模块与UDP协议

    #server
    import socketserver
    class MyServer(socketserver.BaseRequestHandler):
        def handle(self):
            # print('来了?老弟')
            while True:
                data,sock = self.request
                print(self.client_address)      #客户端地址
                print(data.decode('utf-8'))
                sock.sendto(data.upper(),self.client_address)
    
    #村赶紧啊一个基于TCP的对象
    server = socketserver.ThreadingUDPServer(('127.0.0.1',8080),MyServer)
    #启动该服务的对象
    server.serve_forever()
    
    #client
    import socket
    import time
    client = socket.socket(type=socket.SOCK_DGRAM)
    server_address = ('127.0.0.1',8080)
    while True:
        client.sendto(b'hello',server_address)
        data,addr = client.recvfrom(1024)
        print(data.decode('utf-8'),addr)
        time.sleep(1)
    
  • 相关阅读:
    分享自制的C#和VB Code互转工具
    C# winform 学习(一)
    C# winform 学习(二)
    C# winform 学习(二)
    C# Winform 学习(四)
    C# Winform 学习(四)
    C# winform 学习(三)
    C# winform 学习(三)
    C# Winform学习(六)
    C# Winform学习(六)
  • 原文地址:https://www.cnblogs.com/syy1757528181/p/14121287.html
Copyright © 2011-2022 走看看