• 初识网络编程&并发编程


    网络编程

    交互方式

      基于同一台机器上的多个程序之间通信,可基于文件

      基于多台机器之间的通信,可基于网络

    Web程序的两种构架

      C/S Client(客户端) Server(服务端)

      B/S Browser(浏览器) Server(服务端)

      浏览器本身也是客户端的一种

    Mac地址

      唯一标识一台机器  12位16进制

    协议

      IP协议: IP地址的规范

        IPv4协议 32位二进制4点分十进制

        IPv6协议 6冒分16进制组成

        交换机不识别IP地址,因此会一对所有广播,之后一对一单播

        交换机会完成:地址解析协议 arp协议

          通过IP地址找到一台机器的Mac地址

          交换机的广播与单播功能

        rap协议:通过IP地址找到Mac地址

    局域网概念

      路由器:一个区域内的多台机器组成的一个网络

      域名:和IP地址有对应关系,我们访问的域名经过解析也能得到一个IP地址

    网关IP概念

      IP地址另一个作用:区分区域网所在的IP范围

      在一台机器访问局域网外时使用的出口IP

    IP地址

      比Mac简易,随机不固定,可按照区域划分

      IP地址+Mac地址确认机器

      127.0.0.1 本地的回环地址

      0.0.0.0 全网段地址

    端口

      确认本机器上的具体应用

      帮助我们查找机器上的对应服务 

      范围:0-65535

      惯用端口:80,8000之后

    子网掩码

      以相与来确认IP地址的所在范围

    socket

      所有的网络通信的底层均是基于socket做的

      可使用socket模块来实现

    import socket
    sk
    =socket.socket()#创建一个socket对象
    sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1# 表示允许端口复用
    sk.bind(('127.0.0.1',10086))#绑定一个服务端地址,必须为元组(ip,端口) sk.listen()#开始接受客户端给我的连接 conn,addr=sk.accept()#阻塞 conn.send(b'welcome 10086')#给连我的人发消息 msg=conn.recv(1024)#阻塞:直到从连我的人那里就收消息 print(msg)#打印消息 conn.close()#关闭 挂电话 sk.close()#关闭 关机

    而与之对应的

    import socket
    sk
    =socket.socket() sk.connect(('127.0.0.1',10086)) msg=sk.recv(1024) print(msg) txt=input('>>>') sk.send(txt.encode('utf-8')) sk.close()

    TCP协议

      面向连接 

        两台机器之间想要传递信息必须先建立连接

        之后在有了连接的基础上,进行信息的传递

      可靠  

        数据不会丢失或被重复接收

        传递信息后会等待一段时间,若未收到反馈则视为数据丢失,并再次发送

      慢

        TCP协议需要实现三次握手方可连接 (建立全双工的通信协议)

        传递信息后会等待一段时间,若未收到反馈则视为数据丢失,并再次发送

        且必须四次挥手断开连接

      常用于传递大型数据,例如文件,邮件,亦或是远程操控等

    UDP协议

      无连接

        机器之间传递信息不需要建立连接 直接发送即可

      不可靠

        数据可能会丢失

      快

        只负责单向的数据传递

      UDP协议常用于即时通讯类软件 如QQ 微信 飞信 歪歪等

    互联网协议与osi模型

      互联网协议按照功能不同分为osi七层或tcp/ip五层或tcp/ip四层

      osi

        应用层

          应用程序

        表示层

        会话层

        传输层

          端口 TCP/UDP协议 四层交换机 四层的路由器

        网络层

          IP地址相关 IP协议 路由器 三层交换机

        数据链路层

          mac地址相关 arp协议 网卡 二层交换机

        物理层

          中继器 集线器 双绞线

    UDP

    发送端

    import socket
    
    sk=socket.socket(type=socket.SOCK_DGRAM)   #type=socket.SOCK_DGRAM 设置使用UDP协议
    
    sk.bind(('127.0.0.1',10087))  #地址及端口
    
    conn,addr=sk.recvfrom(1024)  #recvfrom接受信息 与发送信息者传来的IP地址及端口号
    
    sk.sendto(b'welcome',addr)  #sendto 发送信息 至指定的 IP地址的端口
    print(conn.decode('utf8'))
    
    sk.close()
    

    接收返回端

    import socket
    
    sk=socket.socket(type=socket.SOCK_DGRAM)
    conn=('127.0.0.1',10087)  #这里写入 自己IP地址 及 端口号
    
    sk.sendto(b'xxx',conn)  #sendto发送信息 及 自身IP地址得端口号
    msg,_=sk.recvfrom(1024)  #recvfrom 接收信息
    print(msg.decode('utf8'))
    
    sk.close()

    粘包

    粘包解决方式

    本次行动接收者server服务端

    import socket
    import struct
    
    sk=socket.socket()
    sk.bind(('127.0.0.1',10089))
    sk.listen()
    
    conn,addr=sk.accept()
    num=conn.recv(4)
    num=struct.unpack('i',num)[0]
    msg=conn.recv(num)
    print(msg.decode('utf-8'))
    
    sk.close()

     本次行动发送者client客户端

    import socket
    import struct
    
    server=socket.socket()
    server.bind(('127.0.0.1',10086))
    server.listen()
    
    conn,addr=server.accept()
    
    ret=conn.recv(4)
    long=struct.unpack('i',ret)[0]
    print(long)
    msg=conn.recv(long)
    print(msg.decode('utf8'))
    conn.recv(1024)

    第二种socket套接字创建方式

    socketserver 模块

    socket模块是socketserver模块的底层模块,socketserver模块是基于socket模块创建的

    自带并行  指多个任务于多个cpu上同时进行

    import socketserver     #导入socketserver模块
    import os
    import hmac     #关于加密算法的内置模块/使用的是md5加密算法
    
    class Myserver(socketserver.BaseRequestHandler):
        def handle(self):   #socketserver模块中固定的方法名,由父类的__init__方法调用
            key_client = 'my server'  #
            conn=self.request   #获取自己IP地址 及 端口号
            txt=os.urandom(32)  #随机生成一个字节串
            conn.send(txt)
            txt=hmac.new(key=key_client.encode(),msg=txt).hexdigest().encode('utf-8')
            # key,msg均为字节,不可加入字符串等,输出为内存地址,hexdigest()转为字符串
            msg=conn.recv(1024)
            if txt==msg:
                print('合法')
            else:
                conn.close()
                print('已执行')
    
    
    obj=socketserver.ThreadingTCPServer(('127.0.0.1',10086),Myserver)
    # 实例化 ((地址及端口),类名)  ps:类名是可更改的,仅handle方法名固定
    obj.serve_forever()
    # 调用socketserver模块中的serve_forever()方法

    进程

    特别注意子进程任务中若使用 input 函数会报 EOF 的错

    进程的创建

      开机启动的程序

      在运行中再开启一个进程


    进程的结束

      正常退出

      出错退出(资源)

      严重出错(非自愿)

      被其他进程杀死

    多级反馈队列

    多个阶层 1→∞ 优先级降序


    sys.argv

       生成一个索引0为此py文件绝对路径的列表


    使用模块操作进程


    import multiprocessing   导入一个多元化的进程模块
    multiple  多元化           processing   进程


    Process  进程类

    正常实现一个调用多次函数的代码

    import os
    import time
    def func(i):
        time.sleep(1)
        print(i, os.getpid())
    print('主:',os.getpid())
    func(0)
    func(1)
    func(2)

    结果会被按顺序,一个一个的打印出来

    这样很稳定,但也很浪费时间

    如果我们尝试着加入进程
    from multiprocessing import Process  导入multiprocessing模块中的Process方法

    from multiprocessing import Process
    
    # multiprocessing是个包
    # Process进程类
    def func(a,b,c):
        time.sleep(1)
        print(a,b,c, os.getpid())
    if __name__=='__main__':
        # p=Process(target=func)
        # p.start()
        print('主:',os.getpid())
        p=Process(target=func,args=(1,2,3))
        p.start() #开启一个进程 异步非阻塞模型 高效率
        print(p.is_alive()) #判断进程是否存活
        print(p.name) #进程名字
        print(p.pid) #pid
        # Process(target=func,args={1:2,2:3,3:4}).start()
        # Process(target=func,args=[1,2,5]).start()
        p.terminate() #结束一个进程 异步非阻塞模型 高效率
        print(p.is_alive())
        time.sleep(0.1)
        print(p.is_alive())
    # 进程之间数据隔离 子进程中返回的值父进程获取不到
    # 上例为异步 start()为开启进程 target=为指定目标函数
    # multiprocessing是个包

    join可以实现进程的阻塞

    import random
    def send_mail(name):
        time.sleep(random.uniform(1,3))
        print('已经给%s发送邮件完毕'%name)
    if __name__=='__main__':
        lst=['alex','yuan']
        p_l=[]
        for name in lst:
            # 阻塞等待一个子进程进程结束
            p=Process(target=send_mail,args=[name,])
            p.start() #异步非阻塞
            p_l.append(p)
            # p.join() #阻塞 直到p对应的进程结束之后才结束阻塞
        print(p_l)
        i=0
        for p in p_l:
            i+=1
            print(i)
            p.join()
            print(i)
        print('所有信息发送完毕')
    
    def func():
        for i in range(20):
            time.sleep(0.5)
            print('in func')
    if __name__=='__main__':
        p=Process(target=func)
        p.daemon=True #设置守护进程
        p.start()
        print('in main')
        time.sleep(3)
        print('finished')
    

    主进程与子进程互不干扰
     主进程执行完毕之后程序不会结束,会等待所有的子进程结束之后才结束
    为什么主进程要等待子进程结束之后才结束
        因为主进程要负责给子进程回收一些系统资源
    守护进程:
        是一个子进程,守护的是主进程
        结束条件:主进程的代码结束,守护进程结束
            守护进程也是个子进程,需要被主进程回收资源

    进程
        主进程的代码结束,守护进程结束
        主进程要回收守护进程(子进程)的资源
        主进程等待其他所有子进程结束
        主进程回收所以子进程的资源

  • 相关阅读:
    使用NPOI将多张图片导入execl
    Oracle计算时间差函数
    Oracle_spatial的函数介绍[转]
    FDO error:Failed to label layer(XXX) for class Default
    您属于哪个版本的程序员[转]
    关于oracle-12514错误的修改方法
    ArcGis在Oracle中常用的sql
    读取XML绑定TreeNode
    HTML中图片热区的使用
    如何查看目前正在使用的Windows10是哪个版本?
  • 原文地址:https://www.cnblogs.com/lttlpp61007188/p/10671084.html
Copyright © 2020-2023  润新知