def __request_close(self):
     active_connections = self.__connections.to_list()
     try:
         while len(active_connections) != 0:
             _, writable, _ = select.select([], active_connections, [], 1)
             for fd in writable:
                 active_connections.remove(fd)
                 BufferWriter.request_close(fd)
                 fd.close()
     except ConnectionResetError:
         pass
 def occupy(self, id: int, uuid: str):
     """
         Occupy a seat for future connections
     :param id: str
     :param uuid: str
     :return: None
     """
     _tmp_cons = self.__worker_id_to_cons.get(id, None)
     # if not settled
     if _tmp_cons is None:
         self.__worker_id_to_cons[id] = uuid
     # check which one is right
     elif isinstance(_tmp_cons, list):
         for _uuid, _con in _tmp_cons:
             if _uuid == uuid:
                 self.put(id, _con)
             # close it
             else:
                 BufferWriter.request_close(_con)
                 _con.close()
Пример #3
0
    def register(self,
                 id_self,
                 content_package: NodeAssignment,
                 con_from=None):
        """
            Register all workers
        :param id_self: id of current worker
        :param content_package: content package that contains address and uuid of all workers
        :return: None
        """
        self.__id = id_self
        if con_from is not None:
            self.__workers.put(Initialization_Server, con_from)

        self_uuid = None
        uuid = content_package.uuid
        writer = BufferWriter()

        # for all slaves
        for id, ip_addr in content_package:
            # slaves who's id before self
            if self_uuid is None and id != self.__id:
                self.__workers.occupy(id, uuid)
            # id of myself
            elif id == self.__id:
                self_uuid = uuid
            # id behind myself
            elif self_uuid is not None:
                # try reach
                worker_con = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                try:
                    worker_con.connect((ip_addr, STAR_NET_WORKING_PORTS))
                    # try register
                    data = {
                        Key.Type: Type_Val.WorkerReports,
                        Key.From: self.__id,
                        Key.To: id,
                        Key.Content: self_uuid
                    }
                    writer.set_content(data)
                    writer.send(worker_con)
                    self.__workers.put(id, worker_con)
                    worker_con.setblocking(False)

                except OSError as error:
                    raise OSError('Error: {}, address: {}'.format(
                        error, ip_addr))

        writer.close()
Пример #4
0
    def __run_deque(self):
        """
            Sending thread function.
        """
        writing_list = {}
        active_connections = []
        while not self.Exit:
            if len(active_connections) == 0 or self.send_que.qsize() > 0:
                try:
                    target, data = self.send_que.get(timeout=1)
                    for send_to in target:
                        fd = self.__connections.find(send_to)
                        if fd is not None:
                            buffer = writing_list.get(fd, BufferWriter())
                            writing_list[fd] = buffer
                            # if can send
                            if buffer.is_done():
                                pkg = {
                                    Key.Type: Type_Val.Normal,
                                    Key.From: self.__connections.get_id(),
                                    Key.To: target,
                                    Key.Content: data
                                }
                                # do encode
                                buffer.set_content(pkg)
                                active_connections.append(fd)
                                # record length
                                self.__data_bytes_sent.value += len(buffer)
                            # put it back
                            else:
                                self.send_que.put(([send_to], data))
                except Empty:
                    continue

            # do send jobs
            if len(active_connections) > 0:
                _, writable, _ = select.select([], active_connections, [], 1)

                for fd in writable:
                    try:
                        buf = writing_list[fd]
                        buf.send(fd)
                        if buf.is_done():
                            active_connections.remove(fd)
                    # ignore exceptions and left it for main thread to handle.
                    except OSError:
                        active_connections.remove(fd)

        for buf in writing_list.values():
            buf.close()
Пример #5
0
def start_star_net(
        nodes: StarNetwork_Initialization_Package) -> ICommunication_Process:

    worker_register = Worker_Register()
    # register
    worker_register.register(Initialization_Server, nodes)
    data = {
        Key.Type: Type_Val.Submission,
        Key.From: Initialization_Server,
        Key.To: -1,
        Key.Content: nodes
    }

    writer = BufferWriter()

    for id, uuid, address in nodes:
        try:
            con = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            # connect
            con.connect((address, STAR_NET_WORKING_PORTS))
            # write key
            data[Key.To] = id
            # serialize and send
            writer.set_content(data)
            writer.send(con)
            # add
            worker_register.identify(id, uuid, con=con)

        except OSError as error:
            for con in worker_register.to_list():
                if isinstance(con, socket.socket):
                    con.close()
            raise OSError('Error: {}, while connecting {}.'.format(
                error, address))

    writer.close()

    if worker_register.check():
        com = Communication_Process(worker_register)
        return com
    else:
        raise OSError('Some of workers didnt respond properly.')


# 解释一下 337 行代码。能够满足 len(active_connections) == 0 or self.send_que.qsize() > 0 条件的,
# 要么是无数据可发,要么是有数据可从队列中取。当出现 Empty Exception 时,一定是无数据可发,即前一项满足
# 因此这时可以直接调用 continue 进入下一轮循环
Пример #6
0
    def __call__(self, nodes: NodeAssignment) -> AbsCommunicationProcess:
        worker_register = WorkerRegister()
        # register
        worker_register.register(Initialization_Server, nodes)
        data = {
            Key.Type: Type_Val.Submission,
            Key.From: Initialization_Server,
            Key.To: -1,
            Key.Content: nodes
        }

        writer = BufferWriter()
        uuid = nodes.uuid

        for id, address in nodes:
            try:
                con = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                # connect
                con.connect((address, STAR_NET_WORKING_PORTS))
                # write key
                data[Key.To] = id
                # serialize and send
                writer.set_content(data)
                writer.send(con)
                # add
                worker_register.identify(id, uuid, con=con)

            except OSError as error:
                for con in worker_register.to_list():
                    if isinstance(con, socket.socket):
                        con.close()
                raise OSError('{}, while connecting {}.'.format(
                    error, address))

        writer.close()

        if worker_register.check():
            com = CommunicationProcess(worker_register)
            return com
        else:
            raise OSError('Some of workers didnt respond properly.')
Пример #7
0
    def run(self):
        """
            Bootstrap method
            start both sending and receiving thread on target socket object
        """
        import threading

        recv_buffer_list = {}
        for fd in self.__connections.to_list():
            recv_buffer_list[fd] = BufferReader()
            fd.setblocking(False)

        # handle writeable event here
        __write_thread = threading.Thread(
            target=self.__run_deque,
            name='Communication process -> deque thread.',
            daemon=True)
        __write_thread.start()

        # handle readable event here
        while not self.Exit:
            active_connections = self.__connections.to_list()

            if len(active_connections) == 0:
                self.Exit = True
                break

            readable, _, excepts = select.select(active_connections, [],
                                                 active_connections, 1)
            # read
            for fd in readable:
                try:
                    buf = recv_buffer_list[fd]
                    buf.recv(fd)
                    if buf.is_done():
                        # record length
                        self.__data_bytes_received.value += len(buf)
                        # do decode
                        data = buf.get_content()
                        _from = data[Key.From]
                        self.recv_que.put((_from, data[Key.Content]))

                except OSError as error:
                    recv_buffer_list[fd].close()
                    addr = 'Unknown'
                    try:
                        addr = fd.getpeername()
                    except Exception:
                        pass
                    self.__report_connection_lost(fd, addr)
                    #
                    # # print DEBUG message
                    # import sys
                    # import traceback
                    # exc_type, exc_value, exc_tb = sys.exc_info()
                    # traceback.print_exception(exc_type, exc_value, exc_tb)
                    # # print DEBUG message

            # handle exception
            for fd in excepts:
                recv_buffer_list[fd].close()
                self.__report_connection_lost(fd, fd.raddr)

            # sleep(ICommunication_Process.Circle_interval)

        __write_thread.join()

        for fd in self.__connections.to_list():
            BufferWriter.request_close(fd)
            fd.close()

        self.recv_que.close()
        self.send_que.close()

        self.__connections.reset()

        print('Communication process exited.')
    def __send_proc(self):
        """
            Sending thread function.
        """
        writing_list = {}
        active_connections = []
        tmp_item = None
        # if not exit and workable
        while not self.__exit_mark or not self.__send_queue.empty() or len(active_connections) != 0:
            # if network is idle, or queue has items
            if len(active_connections) == 0 or self.__send_queue.qsize() > 0:
                if isinstance(tmp_item, tuple):
                    target, data = tmp_item  # cond: (len(a) > 0 and buff is not valid and qsize > 0)
                    tmp_item = None
                else:
                    try:
                        target, data = self.__send_queue.get(
                            timeout=1)  # cond: (len(a) == 0 and qsize == 0) or (qsize > 0)
                    except queue.Empty:
                        continue

                left = list()
                for send_to in target:
                    fd = self.__connections.find(send_to)
                    if fd is None:
                        continue

                    # cond: (send_to is valid) and (fd is valid)
                    buffer = writing_list.get(fd, BufferWriter())
                    writing_list[fd] = buffer
                    # if not full
                    if buffer.is_done():
                        pkg = {
                            Key.Type: Type_Val.Normal,
                            Key.From: self.__connections.get_id(),
                            Key.To: target,
                            Key.Content: data
                        }
                        # cond: (buffer is valid) and (send_to is valid) and (fd is valid)
                        # do encode
                        buffer.set_content(pkg)
                        active_connections.append(fd)
                        # record length
                        self.__data_bytes_sent += len(buffer)
                    # put it back
                    else:
                        if fd not in active_connections:
                            active_connections.append(fd)
                        left.append(send_to)

                if len(left) > 0:
                    # cond: (qfull or not qfull) and tmp_item = None
                    tmp_item = (left, data)
                    if not self.__send_queue.full():
                        try:
                            self.__send_queue.put_nowait(tmp_item)
                            # cond: put valid and len(left) > 0
                            tmp_item = None
                        except queue.Full:
                            pass
            # do send jobs
            if len(active_connections) > 0:
                try:
                    _, writable, excepts = select.select([], active_connections, [], 1)
                except ValueError:
                    continue

                for fd in writable:
                    try:
                        buf = writing_list[fd]
                        buf.send(fd)
                        if buf.is_done():
                            active_connections.remove(fd)
                    # ignore exceptions and left it for main thread to handle.
                    except OSError:
                        active_connections.remove(fd)

                for fd in excepts:
                    active_connections.remove(fd)

        for buf in writing_list.values():
            buf.close()