Пример #1
0
class ZTcpConnection(object):
    DISCONNECTED = 0
    CONNECTING = 1
    CONNECTED = 2
    DISCONNECTING = 3
    def __init__(self, event_loop, name, sock, peer_addr):
        self._event_loop = event_loop
        self._name = name
        self._socket = sock
        self._peer_addr = peer_addr
        self._channel = ZChannel(event_loop, sock.fileno())
        self._channel.set_read_callback(self.handle_read)
        self._channel.set_write_callback(self.handle_write)
        self._channel.set_close_callback(self.handle_close)
        self._channel.set_error_callback(self.handle_error)
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
        self._high_watermark = 64 * 1024 * 1024
        self._state = self.CONNECTING
        self._connection_callback = None
        self._message_callback = None
        self._close_callback = None
        self._write_complete_callback = None
        self._high_watermark_callback = None
        self._context = None
        self._input_buffer = ZBuffer()
        self._output_buffer = ZBuffer()

    def name(self):
        return self._name

    def get_event_loop(self):
        return self._event_loop

    def set_connection_callback(self, cb):
        self._connection_callback = cb

    def set_message_callback(self, cb):
        self._message_callback = cb

    def set_close_callback(self, cb):
        self._close_callback = cb
    
    def set_write_complete_callback(self, cb):
        self._write_complete_callback = cb

    def set_high_watermark_callback(self, cb):
        self._high_watermark_callback = cb

    def _write_complete_callback_wrapper(self):
        self._write_complete_callback(self)

    def set_context(self, ct):
        self._context = ct

    def get_context(self):
        return self._context

    def send(self, data):
        def send_in_loop_wrapper():
            self.send_in_loop(data)

        if self._state == self.CONNECTED:
            if self._event_loop.is_in_loop_thread():
                self.send_in_loop(data)
            else:
                self._event_loop.run_in_loop(send_in_loop_wrapper)

    def send_in_loop(self, data):
        self._event_loop.assert_in_loop_thread()

        if self._state == self.DISCONNECTED:
            logging.warn('disconnected connection, give up writing')
            return

        siz = len(data)
        remaining = siz 
        has_fatal_error = False
        try:
            if not self._channel.is_writing() and self._output_buffer.readable_bytes() == 0: 
                nwritten = self._socket.send(data)
                remaining = siz - nwritten
                if remaining == 0 and self._write_complete_callback:
                    self._event_loop.queue_in_loop(self._write_complete_callback_wrapper)
        except socket.error as e:
            logging.error('ZTcpConnection.send_in_loop fail to write with error %s' %str(e))
            if e.errno != errno.EWOULDBLOCK:
                if e.errno == errno.EPIPE:
                    has_fatal_error = True

        if not has_fatal_error and remaining > 0:
            logging.info('ZTcpConnection.send_in_loop I am going to write more data')
            old_len = self._output_buffer.readable_bytes()
            if old_len + remaining >= self._high_watermark and \
               old_len < self._high_watermark and \
               self._high_watermark_callback:
                siz = old_len + remaining
                def high_watermark_callback_wrapper():
                    self._high_watermark_callback(self, siz)
                self._event_loop.queue_in_loop(_high_watermark_callback_wrapper)
                self._output_buffer.append(data[nwritten:])
                if not self._channel.is_writting():
                    self._channel.enable_writing()

    def handle_read(self, receive_time):
        self._event_loop.assert_in_loop_thread()
        # FIXME recv_into
        try:
            data = self._socket.recv(65536)
            if data:
                self._input_buffer.append(data)
                self._message_callback(self, self._input_buffer, receive_time) 
            else:
                self.handle_close()
        except socket.error as e:
            logging.error('ZTcpConnection.handle_read fail to read with error %s' %str(e))
            self.handle_error()

    def handle_write(self):
        self._event_loop.assert_in_loop_thread()
        if self._channel.is_writing():
            try:
                n = self._socket.send(self._ouput_buffer.tostring())
                self._output_buffer.retrieve(n)
                if self._output_buffer.readable_bytes() == 0:
                    self._channel.disable_writing()
                    if self._write_complete_callback:
                        self._event_loop.queue_in_loop(self._write_complete_callback_wrapper)

                    if self._state == self.DISCONNECTING:
                        self.shutdown_in_loop()
            except socket.error as e:
                logging.error('ZTcpConnection.handle_write fail to write with error %s' %str(e))
        else:
            logging.info('ZTcpConnection.handle_write connection is down, no more writing')

    def _set_state(self, st):
        self._state = st

    def connected(self):
        return self._state == self.CONNECTED

    def handle_close(self):
        self._event_loop.assert_in_loop_thread()
        assert self._state == self.CONNECTED or self._state == self.DISCONNECTING
        self._set_state(self.DISCONNECTED)
        self._channel.disable_all()
        self._connection_callback(self)
        self._close_callback(self)

    def handle_error(self):
        logging.error('ZTcpConnection.handle_error error happened')

    def shutdown_write(self):
        if self._state == self.CONNECTED:
            self._set_state(self.DISCONNECTING)
            self._event_loop.run_in_loop(self.shutdown_write_in_loop)

    def shutdown(self):
        if self._state == self.CONNECTED:
            self._set_state(self.DISCONNECTING)
            self._event_loop.run_in_loop(self.shutdown_in_loop)

    def shutdown_write_in_loop(self):
        self._event_loop.assert_in_loop_thread()
        # FIXME what if channel is writing ?
        if not self._channel.is_writing():
            self._socket.shutdown(socket.SHUT_WR)

    def shutdown_in_loop(self):
        self._event_loop.assert_in_loop_thread()
        # FIXME what if channel is writing ?
        if not self._channel.is_writing():
            self._socket.shutdown(socket.SHUT_RDWR)

    def set_tcp_no_delay(on):
        if on:
            self._socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
        else:
            self._socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 0)

    def connection_established(self):
        self._event_loop.assert_in_loop_thread()
        assert self._state == self.CONNECTING
        self._set_state(self.CONNECTED)
        self._channel.tie(self)
        self._channel.enable_reading()
        self._connection_callback(self)

    def connection_destroyed(self):
        self._event_loop.assert_in_loop_thread()
        if self._state == self.CONNECTED:
            self._set_state(self.DISCONNECTED)
            self._channel.disable_all()
            self._connection_callback(self)
        self._channel.unregister()
Пример #2
0
 def send(self, tcp_conn, message_str):
     buf = ZBuffer()
     buf.append(message_str)
     buf.prepend_int32(socket.htonl(len(message_str)))
     tcp_conn.send(buf.retrieve_all_as_string())