• 计算机网络(4): socket select使用:聊天室模版


    知识点:

    如上所示,用户首先将需要进行IO操作的socket添加到select中,然后阻塞等待select系统调用返回。当数据到达时,socket被激活,select函数返回。用户线程正式发起read请求,读取数据并继续执行。

    从流程上来看,使用select函数进行IO请求和同步阻塞模型没有太大的区别,甚至还多了添加监视socket,以及调用select函数的额外操作,效率更差。但是,使用select以后最大的优势是用户可以在一个线程内同时处理多个socket的IO请求。用户可以注册多个socket,然后不断地调用select读取被激活的socket,即可达到在同一个线程内同时处理多个IO请求的目的。而在同步阻塞模型中,必须通过多线程的方式才能达到这个目的。

    使用:

    readable, writable, exceptional = select.select(inputs, outputs, inputs)

    第一个参数是我们需要监听可读的套接字, 第二个参数是我们需要监听可写的套接字, 第三个参数使我们需要监听异常的套接字, 第四个则是时间限制设置.

    如果监听的套接字满足了可读可写条件, 那么所返回的can,read 或是 can_write就会有值了, 然后我们就可以利用这些返回值进行随后的操作了。相比较unix 的select模型, 其select函数的返回值是一个整型, 用以判断是否执行成功

    案例:

    1)服务器

    import socket,select
    
    
    # Function to broadcast chat messages to all connected clients
    def broadcast_data(sock, message):
        # Do not send the message to master socket and the client who has send us the message
        for socket in CONNECTION_LIST:
            if socket != server_socket and socket != sock:
                try:
                    socket.send(message)
                except:
                    # broken socket connection may be, chat client pressed ctrl+c for example
                    socket.close()
                    CONNECTION_LIST.remove(socket)
    
    
    if __name__ == "__main__":
    
        # List to keep track of socket descriptors
        CONNECTION_LIST = []
        RECV_BUFFER = 4096  # Advisable to keep it as an exponent of 2
        PORT = 22
    
        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # this has no effect, why ?
        server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server_socket.bind(("0.0.0.0", PORT))
        server_socket.listen(10)
    
        # Add server socket to the list of readable connections
        CONNECTION_LIST.append(server_socket)
    
        print("Chat server started on port " + str(PORT))
    
        while 1:
            # Get the list sockets which are ready to be read through select
            read_sockets, write_sockets, error_sockets = select.select(CONNECTION_LIST, [], [])
    
            for sock in read_sockets:
                # New connection
                if sock == server_socket:
                    # Handle the case in which there is a new connection recieved through server_socket
                    sockfd, addr = server_socket.accept()
                    CONNECTION_LIST.append(sockfd)
                    print("Client (%s, %s) connected" % (addr,sockfd))
    
                    #*****这里修改了服务器********
                    broadcast_data(sockfd,("[%s:%s] entered room
    " % (addr,sockfd)).encode('utf-8'))
    
                # Some incoming message from a client
                else:
                    # Data recieved from client, process it
                    try:
                        # In Windows, sometimes when a TCP program closes abruptly,
                        # a "Connection reset by peer" exception will be thrown
                        data = sock.recv(RECV_BUFFER)
                        if not data or data.decode('utf-8') == 'exit':
                            server_socket.close()
    
                        if data:
                            broadcast_data(sock, ("
    " + '<' + str(sock.getpeername()) + '> ' + data.decode('utf-8')).encode('utf-8'))
                            broadcast_data(sock,data)
    
                    except:
                        broadcast_data(sock, ("Client is offline").encode('utf-8'))
                        print("Client is offline")
                        sock.close()
                        CONNECTION_LIST.remove(sock)
                        continue

    2)客户端

    # telnet program example
    import socket, select, string, sys
    
    
    # def prompt():
    #     sys.stdout.write('<You> ')
    #     sys.stdout.flush()
    
    
    # main function
    if __name__ == "__main__":
    
        if (len(sys.argv) < 3):
            print('Usage : python telnet.py hostname port')
            sys.exit()
    
        host = sys.argv[1]
        port = int(sys.argv[2])
    
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(2)
    
        # connect to remote host
        try:
            s.connect((host, port))
        except:
            print('Unable to connect')
            sys.exit()
    
        print('Connected to remote host. Start sending messages')
    
    
        while 1:
            rlist = [sys.stdin, s]
    
            # Get the list sockets which are readable
            read_list, write_list, error_list = select.select(rlist, [], [])
    
            for sock in read_list:
                # incoming message from remote server
                if sock == s:
                    data = sock.recv(4096)
                    if not data:
                        print('
    Disconnected from chat server')
                        sys.exit()
                    else:
                        # print data
                        data = data.decode("utf-8")
                        sys.stdout.write(data)
                        print(len(data))
    
                    break

    https://www.cnblogs.com/zhiyong-ITNote/p/7553694.html

    https://blog.csdn.net/weixin_41010318/article/details/80257177

  • 相关阅读:
    Python 学习笔记(七)Python字符串(三)
    Python 学习笔记(七)Python字符串(二)
    Python 学习笔记(六)Python第一个程序
    Python 学习笔记(五)常用函数
    Python 学习笔记(四)数字(二)
    行为型模式之责任链模式
    python_frm组件
    django之models学习总结
    HTTP协议
    事件委托
  • 原文地址:https://www.cnblogs.com/Plorde/p/12305292.html
Copyright © 2020-2023  润新知