def serve_forever(host, port, childnum):
    # create, bind. listen
    listen_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # re-use the port
    listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    # put listening socket into non-blocking mode
    listen_sock.setblocking(0)

    listen_sock.bind((host, port))
    listen_sock.listen(BACKLOG)

    print('Listening on port %d ...' % port)

    # read, write, exception lists with sockets to poll
    main_rlist, wlist, elist = [listen_sock], [], []

    # prefork children
    for index in range(childnum):
        create_child(index, listen_sock)
        # watch the socket
        main_rlist.append(CHILDREN[index]['pipe'])

    FREE_CHILD_COUNT = childnum

    while True:
        # read list with sockets to poll
        rlist = main_rlist.copy()

        # if we don't have a free child, stop accepting connections
        # (although the kernel will still be queueing up new connections
        # because of the BACKLOG)
        if FREE_CHILD_COUNT == 0:
            rlist.remove(listen_sock)

        # block in select
        readables, writables, exceptions = select.select(rlist, wlist, elist)

        if listen_sock in readables: # new client connection, we can accept now
            try:
                conn, client_address = listen_sock.accept()
            except __HOLE__ as e:
                code, msg = e.args
                if code == errno.EINTR:
                    continue
                else:
                    raise

            # find a free child to pass the connection to
            for child in CHILDREN:
                if child['status'] == FREE: # free
                    # mark as busy
                    child['status'] = BUSY

                    # pass the connection's descriptor to the child
                    write_fd(child['pipe'], conn.fileno())
                    # server doesn't need this connection any more
                    conn.close()

                    FREE_CHILD_COUNT -= 1
                    break
            else:
                # this shouldn't happen
                raise Exception('No free child found')

        # find newly-available children
        for child in CHILDREN:
            child_pipe = child['pipe']
            if child_pipe in readables:
                data = child_pipe.recv(1)
                if not data:
                    # child terminated
                    raise Exception('Child terminated unexpectedly')
                child['status'] = FREE # free
                FREE_CHILD_COUNT += 1
dataset/ETHPy150Open rspivak/csdesign/server04.py/serve_forever