zoukankan      html  css  js  c++  java
  • Socket--selecct的用法

    Select的用法(select是一个单线程)
    s.bind(('127.0.0.1', 8888))
    s.listen(5)
    r_list = [s, ]
    num = 0
    while True:
        print(u"开始进入监听状态...")
        rl, wl, error = select.select(r_list, [], [], 10)#所有的过程都是单线程
    要操作的对象都会放在rl里面的
        # 第一次执行循环体:客户端建立的连接的时候,rl和r_list分别是[s,]和[s,]
        #                  执行连接之后,r_list变为了[s,conn],建立连接会走if逻辑
        # 第二次执行循环体:有需要读取的时候,rl和r_list分别是[conn,]和[s,conn],执行else逻辑
        # 。。。。。如果客户端没有发送消息rl是[]
        ##第n次执行循环体:rl和r_list分别是[conn,]和[s,conn],执行else逻辑
        #简单来说rl会在建立连接后,添加socket对象,但是以后就不会在添加socket对象了,
        #因为建立连接的事件只会被select监听到一次。
        #然后select就一直监听已经建立的连接对象是否有数据发来了。当有异常的时候,会把链接对象从rl中删除掉。
        num += 1
        print(u'执行次数%s'% num)
        print("rl's length is %s" % len(rl))
        print("r_list length %s" % len(r_list))
        print([i for i in rl])
        for fd in rl:
            if fd == s:#客户端连接的时候会被触发一次
                conn, addr = fd.accept()#建立连接
                r_list.append(conn)#加入到监听列表里面
                msg = conn.recv(200)#收取从客户端来的数据
                conn.sendall(('first----%s' % msg.upper()).encode("utf-8"))#给客户端回复数据
            else:#客户端建立连接后发来了新的消息,会执行else分支
                try:
                    msg = fd.recv(200)
                    fd.sendall(msg.upper())#把收到的数据转换为大写后,发回给客户端
                except (ConnectionAbortedError, ConnectionResetError):
                    r_list.remove(fd)
    s.close()
    
    Select的解释
    
    fd_r_list, fd_w_list, fd_e_list = select.select(rlist, wlist, xlist, [timeout])
    
    参数: 可接受四个参数(前三个必须)
    rlist: 等待准备阅读
    wlist: 等待准备写作(一般不使用)
    xlist: 等待“例外情况”
    timeout: 超时时间,表示多少秒监听一次,如果为None或者为空则阻塞直到至少有一个文件描述符已经准备好了。
    
    s.bind(('127.0.0.1', 8888))
    s.listen(5)
    r_list = [s, ]
    num = 0
    while True:
        print(u"开始进入监听状态...")
        rl, wl, error = select.select(r_list, [], [], 10)
        # 第一次执行循环体:客户端建立的连接的时候,rl和r_list分别是[s,]和[s,]
        #                  执行连接之后,r_list变为了[s,conn],建立连接会走if逻辑
        # 第二次执行循环体:有需要读取的时候,rl和r_list分别是[conn,]和[s,conn],执行else逻辑
        # 。。。。。如果客户端没有发送消息rl是[]
        ##第n次执行循环体:rl和r_list分别是[conn,]和[s,conn],执行else逻辑
        #简单来说rl会在建立连接后,添加socket对象,但是以后就不会在添加socket对象了,
        #因为建立连接的事件只会被select监听到一次。
        #然后select就一直监听已经建立的连接对象是否有数据发来了。当有异常的时候,会把链接对象从rl中删除掉。
        num += 1
        print(u'执行次数%s'% num)
        print("rl's length is %s" % len(rl))
        print("r_list length %s" % len(r_list))
        print([i for i in rl])
        for fd in rl:
            if fd == s:#客户端连接的时候会被触发一次
                conn, addr = fd.accept()#建立连接
                r_list.append(conn)#加入到监听列表里面
                msg = conn.recv(200)#收取从客户端来的数据
                conn.sendall(('first----%s' % msg.upper()).encode("utf-8"))#给客户端回复数据
            else:#客户端建立连接后发来了新的消息,会执行else分支
                try:
                    msg = fd.recv(200)
                    fd.sendall(msg.upper())#把收到的数据转换为大写后,发回给客户端
                except (ConnectionAbortedError, ConnectionResetError):
                    r_list.remove(fd)
    s.close()
    
    
    服务端的代码
    r_list:select需要监听的文件对象。
    开始的时候我初始化这个列表:r_list = [s, ] 
    把socket放进去了。
    
    1)开始执行:rl, wl, error = select.select(r_list, [], [], 10)
    等待10秒,看看有没有人来建立连接,如果没有
    2)代码继续执行从num += 1开始执行,然后执行到if,if和else并没有被触发
    因为rl里面是空,什么都没有。
    继续下一次循环,从1开始执行,如此反复。
    
    
    如果有客户端进行连接了呢?开始代码向下执行:
    rl从[]---->[s],
    代码继续执行从num += 1开始执行,然后执行到if
    if 的条件被触发了,客户端和server的连接被建立了。
        if fd == s:#客户端连接的时候会被触发一次
                conn, addr = fd.accept()#建立连接
                r_list.append(conn)#加入到监听列表里面
                msg = conn.recv(200)#收取从客户端来的数据
                conn.sendall(('first----%s' % msg.upper()).encode("utf-8"))#给客户端回复数据
    结束当前循环,继续从1)开始。这个时候除了监控s对象有没有新建连接
    请求外,conn也被监控看看客户端是否发来了数据。
    如果没有新建链接也没有conn被发来数据,rl=[] -->if和else都不会被执行
    继续下一次循环,从1)开始执行,如此反复。
    
    
    
    r_list包含了conn对象(被监听),如果客户端发来数据,
    rl, wl, error = select.select(r_list, [], [], 10)
    rl=[] 变成了[conn],会触发else:操作,从连接中读取发来的数据,并
    转换为大写之后返回给客户端
    
    try:
                    msg = fd.recv(200)
                    fd.sendall(msg.upper())#把收到的数据转换为大写后,发回给客户端
                except (ConnectionAbortedError, ConnectionResetError):
                    r_list.remove(fd)
    继续下一次循环,从1)开始执行,如此反复。
    
    15.3.客户端的情况 
    
    rl:客户端既没有连接,有没有发送数据的情况下,rl一直是[]
    只有在客户端有动作的时候,
    它才从[]--->[s]或者[conn1]或者[conn1,conn2...]
    1)新建连接的请求,s(socket对象)
    2)已经建立连接后发送数据的连接对象conn对象(可能是一个也可能是多个。)
    
    客户端的代码
    
    import socket
    flag = 1
    s = socket.socket()
    s.connect(('127.0.0.1', 8888))
    while flag:
        input_msg = input('input>>>')
        if input_msg == '0':
            break
        s.sendall(input_msg.encode())
        msg = s.recv(1024)
        print(msg.decode())
    s.close()
  • 相关阅读:
    【原创】只需3行代码,Python基础面试题:循环报数3的出圈
    【原创】MySQL同时取出最大值和最小值所在整行
    【原创】Python打印立方米
    【Python】如何像cmd一样操作系统命令
    【群答疑20210525-3】MySQL限制时间是当前月,或者月区间查询
    【群答疑20210525-1】MySQL列名相同,出现两列问题
    【原创】爬虫反爬基础常见类型总结
    【原创】Python基础面试题:按照年龄判断未成年还成年(条件语句)
    【原创】Python基础:你真的知道and和or的用法吗
    【Python】 读写MySQL
  • 原文地址:https://www.cnblogs.com/hzyimen/p/12393306.html
Copyright © 2011-2022 走看看