python-select / tcp通信

在实际开发中,经常会遇到select 和 socket进行搭配使用,在此个人做一个小结

一. select函数

1 函数原型

readable, writeable, exceptionable = select.select(rlist, wlist, xlist,timeout)

入参的前三个是三个列表,代表要监听的列表,通常第一个是读列表, 第二个是写列表,第三个则是异常列表,第四个代表select阻塞的时间(s)

返回值也是三个列表,分别是是监听列表中发生改变的成员,例如 rlist中一共监听了100个socket,如果有2个socket接收到消息,则readable中就应该有2个成员

但是特别注意的是,wlist中的所有成员都会复制到writeable

2 函数的实际应用--tcp--server

该脚本可以实现多客户端连接进行交互

import socket
import select
import sys
# import queue
import Queue
import signal


def server_start(server_ip, sever_port):
    try:
        # create a server socket /tcp
        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # reuse socket
        # bind the server socket
        server_socket.bind((str(server_ip), int(sever_port)))
        server_socket.setblocking(False)  # socket is non_blocking
        # set the max listen client number = 10 and start listen
        server_socket.listen(10)
    except socket.error as err:
        print("server start error, reason = " + str(err))
        sys.exit(1)

    rlist = [server_socket]  # put the server_socket to list
    wlist = []
    message_queues = {}  # store the message with clients and server
    client_queues = {}  # store the client's address
    while True:
        try:
            timeout = 3  # if no event occur, select function will be return
            readable, writeable, exceptionable = select.select(rlist, wlist, rlist, timeout)
            print("select again")
        except select.error as err:
            print("select module init error, reason = " + str(err))
            sys.exit(1)
        # handle the readable
        for s in readable:
            # new client is coming
            if s is server_socket:
                client_socket, client_address = s.accept()
                client_socket.setblocking(False)
                rlist.append(client_socket)
                message_queues[client_socket] = Queue.Queue()  # create a message queue for new client
                client_queues[client_socket] = client_address  # store the new client address
                print("new client is connecting, client is " + str(client_address))
            # new data is coming or client is disconnected
            else:
                try:
                    # receive data
                    data_buff = s.recv(1024)
                except socket.error as err:
                    print("receive data err!" + str(client_queues[s]))
                if data_buff:
                    print(str(client_queues[s]) + "coming data, data = " + str(data_buff))
                    message_queues[s].put(data_buff)  # put new data to message queue
                    if s not in wlist:  # update the wlist to handle the recived data
                        wlist.append(s)
                else:  # client is disconnected
                    print("a client is disconnected " + str(client_queues[s]))
                    del message_queues[s]
                    del client_queues[s]
                    rlist.remove(s)
                    if s in wlist:
                        wlist.remove(s)
                    if s in writeable:
                        writeable.remove(s)
        # handle the writeable
        for s in writeable:
            try:
                msg_que = message_queues.get(s)  # get the message queue
                if msg_que is not None:  # the queue is exist
                    while not msg_que.empty(): # handle the message until the queue is empty
                        msg = msg_que.get_nowait()  # get the msg from message queue
                        # do something....
                        s.send(msg + str(client_queues[s]))
                        print("send data, data = " + str(msg + str(client_queues[s])))
                    print("exit")
                    wlist.remove(s)  # no message in queue

            except Queue.Empty:  # client socket is disconnected
                wlist.remove(s)  # update the wlist
        # handle the exceptionable
        for s in exceptionable:
            print("error!" + "(" + str(client_queues[s]) + ")")
            rlist.remove(s)
            if s in wlist:
                wlist.remove(s)
            del message_queues[s]
            del client_queues[s]
            pass


if __name__ == '__main__':
    signal.signal(signal.SIGINT, quit)
    signal.signal(signal.SIGTERM, quit)
    server_start("10.74.133.94", "8080")
    while True:
        pass

 

上一篇:RabbitMq-Work queues工作队列模式(二)


下一篇:Dyno-queues 分布式延迟队列 之 辅助功能