zoukankan      html  css  js  c++  java
  • select简单示例,有注释

    全部都在代码中:

    import select
    import socket
    import queue
    
    """
    简单的select 实现echo server
    个人理解:
    select 编程思想,让select去去判断能不能读或能不能写。
    如果能读或能写,select就会告知readable或writeable,这时就得让文件句柄去读或写,
    在这里是scoket,recv()或scoket.send()去执行实际的操作
    """
    server = socket.socket()   # 获取一个套接字
    server.setblocking(False)  # 设置为非阻塞模式
    server.bind(('127.0.0.1',9001))  # 绑定ip和端口
    server.listen(5)           # 启动监听,到这步可以在netstat 看到监听状态,如果没有server.accept()的话,客户端的连接会被拒绝
    
    inputs = [ server ]        # 设置输入队列,当server的监听收到客户端连接时,select会认为这个server为可读,就得让server.accpet()去接收客户端连接
                               # 或者当socket有新的数据发送过来时,select会认为这个socket是可读的,就得去让socket的recv()去接收数据
    outputs = []               # 当socket可以发送数据给对端时,select会认定这个socket是
    message_queue = {}         # 消息队列,key值为socket套接字
    n = 0                      # 体现while循环了多少次
    while inputs:              # inputs中是否存在值
        print("waiting for connect..., %s"%n)
        readable , writeable ,exceptions = select.select(inputs,outputs,inputs)             # select就像一个非常强大的监视器,监视各个文件句柄的是否可读可写。
    
        for s in readable:                  # 循环可读的。
            if s is server:                 # 如果是server套接字
                print("server can read...")
                conn, addr = s.accept()          # 就接收客户端连接
                print("welcome (%s,%s) to connect..."%addr)
                inputs.append(conn)              # 将客户端套连接接字放入inputs,而不是马上接收或发生数据。
                # s.setblocking(False)
    
            else:                             # 如果不是server套接字
                print("a scoket can read:" ,s.getpeername())    # 只有当有数据发送过来时才会把那个套接字放在readable里
                try:
                    data = s.recv(1024)       # 就表明客户端连接套接字收到了客户端发送来的数据
                except Exception as e:   # 客户端进程被强制关闭,导致客户端发送rst包。 ConnectionResetError
                    print(e)
                    inputs.remove(s)          # 如果客户端退出,就讲这个套接字从inputs中移除
                    if s in outputs:          # 如果这个套接字存在于outputs中,也将这个套接字从outputs中移除,因为客户端都关闭了
                                              # 还将这个套接字放在outputs中没有了,发不了数据了啊。
                        outputs.remove(s)
                    s.close()                 # 记得关闭这个套接字
                    break                     # 这里要break,因为s.recv(1024)异常了,data根本就没有被定义,下面的if data就会报错。
    
                if data:                      # 如果有数据
                    print("recv from %s:%s"%(s.getpeername(),data.decode()))
                    message_queue[s] = queue.Queue()      # 将收到的数据放入消息队列中
                    message_queue[s].put(data)
                    outputs.append(s)                     # 因为是echo server,所有有道数据后就得原有返回数据,但是这里不立即返回,而是交由select.
                else:
                    print("the client (%s,%s) is closed "%s.getpeername())             # 如果data为空,表示客户端正常关闭连接,客户端发送了fin.
                    if s in outputs:                      # 客户端关闭了,这个套接字也就没必要放在outputs和inputs中了
                        outputs.remove(s)
                    inputs.remove(s)
                    del message_queue[s]                  # 消息队列也可以清除
                    s.close()                             # 关闭套接字
    
        for s in writeable:                               # 如果可写,“好像ouputs有连接的套接字 存在就是可写的。”
            try:
                data = message_queue[s].get_nowait()      # 获取要发送的消息
            except queue.Empty:                           # 消息队列为空也是可写的。
                print("outpt queue for (%s,%s) in empty"%s.getpeername())
                outputs.remove(s)                         # 因为是echo server,所以消息队列为空时,说明已经回应了数据给对端,就不用一直去判断这个套接字是否可写了。
                # s.close()     # 没有数据可发送并不代表要关闭socket
            else:
                print("send data to client (%s,%s)"%s.getpeername())
                s.send(data)
                # outputs.remove(s)           # 发送完一条数据后,其实不能将他移除,因为有可能对端非常迅速的发了多条消息过来,而服务器一条消息都还没来得及回复,
                                              # 服务器的消息将会都放在队列中等待发送,所以这里的让队列为空时在把套接字从outputs中移除。
    
        for s in exceptions:                # 如果发生错误
            print("expect happend on (%s,%s)"%s.getpeername())
            inputs.remove(s)                # 将这个套接字从inouts,outputs中移除
            if s in outputs:
                outputs.remove(s)
            s.close()                       # 连接要关闭
            del message_queue[s]            # 消息队列也要关闭
        n += 1                              # 看看while循环可多少次
    
    waiting for connect..., 0
    server can read...
    welcome (127.0.0.1,3137) to connect...
    waiting for connect..., 1
    server can read...
    welcome (127.0.0.1,3138) to connect...
    waiting for connect..., 2
    a scoket can read: ('127.0.0.1', 3137)   # 这里说明第一个客户端套接字在readable里,下面也没看到第二个客户端在readable里直到第二个客户端发送数据过来,也就是说select只是把可读的返回给了readable里。
    recv from ('127.0.0.1', 3137):this is the 1st client
    waiting for connect..., 3
    send data to client (127.0.0.1,3137)
    waiting for connect..., 4
    outpt queue for (127.0.0.1,3137) in empty
    waiting for connect..., 5
    a scoket can read: ('127.0.0.1', 3138)
    recv from ('127.0.0.1', 3138):this is the 2nd client
    waiting for connect..., 6
    send data to client (127.0.0.1,3138)
    waiting for connect..., 7
    outpt queue for (127.0.0.1,3138) in empty
    waiting for connect..., 8
    a scoket can read: ('127.0.0.1', 3138)
    recv from ('127.0.0.1', 3138):2nd haha
    waiting for connect..., 9
    send data to client (127.0.0.1,3138)
    waiting for connect..., 10
    outpt queue for (127.0.0.1,3138) in empty
    waiting for connect..., 11
    a scoket can read: ('127.0.0.1', 3137)
    recv from ('127.0.0.1', 3137):1st hello
    waiting for connect..., 12
    send data to client (127.0.0.1,3137)
    waiting for connect..., 13
    outpt queue for (127.0.0.1,3137) in empty
    waiting for connect..., 14
    a scoket can read: ('127.0.0.1', 3138)
    recv from ('127.0.0.1', 3138):2nd wiil killed by os
    waiting for connect..., 15
    send data to client (127.0.0.1,3138)
    waiting for connect..., 16
    outpt queue for (127.0.0.1,3138) in empty
    waiting for connect..., 17
    a scoket can read: ('127.0.0.1', 3138)
    [WinError 10054] 远程主机强迫关闭了一个现有的连接。
    waiting for connect..., 18
    a scoket can read: ('127.0.0.1', 3137)
    recv from ('127.0.0.1', 3137):1st wiil closed by socket.close()
    waiting for connect..., 19
    send data to client (127.0.0.1,3137)
    waiting for connect..., 20
    outpt queue for (127.0.0.1,3137) in empty
    waiting for connect..., 21
    a scoket can read: ('127.0.0.1', 3137)
    the client (127.0.0.1,3137) is closed 
    waiting for connect..., 22

     

    客户端:

    import socket
    
    s = socket.socket()
    s.connect(('127.0.0.1',9001))
    
    while True:
        data = input(">> ").strip()
        if data == "":
            continue
        if data == "q":
            s.close()
            break
        s.send(bytes(data,encoding="utf-8"))
        data = s.recv(1024)
        print("recv:",data.decode())
    

      

  • 相关阅读:
    [BZOJ] 3191 [JLOI2013]卡牌游戏
    [LUOGU] P1466 集合 Subset Sums
    [LUOGU] P1113 杂物
    [BZOJ] 1003 [ZJOI2006]物流运输
    poj 2479 最大连续子段和
    C#学习第九弹之委托
    C#学习第八弹之线程基础理解
    C#学习第七弹之WPF
    hdu 2030 汉字的编码方式
    hdu 1559 暴力
  • 原文地址:https://www.cnblogs.com/owasp/p/5599290.html
Copyright © 2011-2022 走看看