zoukankan      html  css  js  c++  java
  • 网络传输中的两个阶段、阻塞IO、非阻塞IO和多路复用

      今天学习了网络传输中的两个阶段、阻塞IO、非阻塞IO和多路复用

      一、网络传输中的两个阶段

      分别是 waitdata 和 copydata

      send就是copydata

      recv是waitdata和copydata

      二、阻塞  IO

      无论是线程 进程  还是线程 进程池  统统都是阻塞IO

      三、非阻塞IO

      最直接体现 所有和读写相关的函数 都不会阻塞

      意味着 在读写时  并不能确定目前是否可以读写 一旦不能读写就抛出异常

      只能使用 try except 来判断是否可以读写

      必须不断的执行系统调用  CPU占用特别高 当没有任何数据要处理的时候简直就是病毒

      

    #非阻塞IO模型 客户端
    import socket
    c = socket.socket()
    c.connect(('127.0.0.1',9999))
    while True:
        msg = input('>>>:')
        if not msg:continue
        c.send(msg.encode('utf-8'))
        data = c.recv(1024)
        print(data.decode('utf-8'))
    #非阻塞IO模型 服务器
    import socket
    server = socket.socket()
    server.setsocket(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    server.bind(('127.0.0.1',9999))
    server.listen(5)
    server.setblocking(False)
    def data_handler(conn):
        print('一个新连接..')
        while True:
            data = conn.recv(1024)
            conn.send(data.upper())
    clients = []
    send_datas = []
    del_datas = []
    closed_cs = []
    while True:
        try:
            conn,addr = server.accept()
            clients.append(conn)
        except BlockingIOError:
            for c in clients:
                try:
                    data = c.recv(1024)
                    if not data:
                        c.close()
                        closed_cs.append(c)
                        continue
                    print('收到%s'%data.decode('utf-8'))
                    send_datas.append((c,data))
                except BlockingIOError:
                    pass
                except ConnectionResetError:
                    c.close()
                    closed_cs.append(c)
            for data in send_datas:
                try:
                    data[0].send(data[1].upper())
                    del_datas.append(data)
                except BlockingIOError:
                    continue
                except ConnectionResetError:
                    data[0].close()
                    closed_cs.append(data[0])
                    del_datas.append(data)
            for d in del_datas:
                send_datas.remove(d)
            del_datas.clear()
            for c in closed_cs:
                clients.remove(c)
            closed_cs.clear()

      四、多路复用

        核心函数select

        帮你检测所有的连接 找出可以被处理(可以读写)的连接

        作为处理数据的一方 不再需要重复去向系统询问 select给你谁 你就处理谁 没给就不处理

    #多路复用模型  客户端
    import socket
    c = socket.socket()
    c.connect(('127.0.0.1',9999))
    while True:
        msg = input('>>>:')
        if not msg:continue
        c.send(msg.encode('utf-8'))
        data = c.recv(1024)
        print(data.decode('utf-8'))
    #多路复用模型  服务器
    import socket
    import select
    #select帮你从一堆连接中找出来需要被处理的连接
    server = socket.socket()
    #重用端口
    server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    server.bind(('127.0.0.1',9999))
    server.listen(5)
    #设置是否为阻塞  默认阻塞
    server.setblocking(False)
    #需要检测是  是否可读取的列表 (recv就是一个读取操作)
    rlist = [server,]
    #需要检测的   是否写入的列表    (send就是写入操作)
    wlist = []
    #需要发送的数据 目前是因为 我们要把接受的数据再发回去  所以搞了这个东西  正常没有这种需求
    #目前客户端与服务器端 交互 是必须客户端发送数据 服务端才能返回数据 正常没有这种需求
    dic = {}
    
    while True:    #用于检测需要处理的连接 需要不断检测 所以循环
        #rl目前可读的客户端列表  wl目前可写的客户端列表
        rl,wl,xl = select.select(rlist,wlist,[])    #select默认阻塞  阻塞到任意一个连接可以被处理
        print(len(rl))
        #处理可读的socket
        for c in rl:
            #无论是客户端还是服务端只要可读就会执行到这里
            if c == server:
                #接受客户端的连接请求(一个读操作)
                conn,addr = c.accept()
                #将新连接也交给select来检测
                rlist.append(conn)
            else:    #不是服务器 就是客户端 客户端可读 可以执行recv
                try:
                    data = c.recv(1024)
                    if not data:
                        c.close()
                        rlist.remove(c)
                    print('%s 发送 %s'%(c,data.decode('utf-8')))
                    #给客户端发送数据前要保证目前可以发送 将客户端加入检测列表
                    wlist.append(c)    #正常开发中 不可能必须客户端发送数据过来后才能给客户端发送
                    #可以这个添加到检测列表的操作 应该建立连接后立即执行
                    #要发送的数据
                    dic[c] = data
                except ConnectionResetError:
                    #客户端关闭连接
                    c.close()
                    rlist.remove(c)
        #处理可写的socket
        for c in wl:
            print(c)
            try:
                c.send(dic[c].upper())
                #删除数据
                dic.pop(c)
                #从检测列表中删除已发送完成的客户端
                wlist.remove(c)
            except ConnectionResetError:
                c.close()    #关闭连接
                dic.pop(c)    #删除要发送的数据
                wlist.remove(c)    #从待检测的列表中删除
            except BlockingIOError:    #可能缓存满了 发不了
                pass
  • 相关阅读:
    存储过程系列之存储过程sql查询存储过程的使用
    SQL Server 连接字符串和身份验证详解
    存储过程
    Objective-C:MRC(引用计数器)在OC内部的可变对象是适用的,不可变对象是不适用的(例如 NSString、NSArray等)
    Objective-C:MRC(引用计数器)获得对象所有权的方式(init、retain、copy等)
    Objective-C:MRC手动释放对象内存举例(引用计数器)
    C语言:内存的分配与管理
    Objective-C:继承、分类(Category、extension)、协议(protocol),个人理解,仅供参考
    Objective-C:在类中设置不同协议
    Objective-C:继承的体现
  • 原文地址:https://www.cnblogs.com/xiaocaiyang/p/9960492.html
Copyright © 2011-2022 走看看