计算机网络(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

原文地址:https://www.cnblogs.com/Plorde/p/12305292.html