Python socket.send успешно выполняется, когда соединение находится в состоянии «closed_wait» - PullRequest
0 голосов
/ 05 апреля 2020

Я экспериментирую с сокетами.
Я установил простой прослушиватель netcat и у меня есть следующий код python.
Я создаю сокет TCP и устанавливаю его без блокировки после настройки Параметры поддержки активности TCP.

Когда слушатель уничтожен, соединение переходит в состояние «close_wait».
При первом вызове socket.send данные соединения close_wait отправляются в буфер .
Во второй раз метод "socket.send" вызывается как исключение "Broken Pipe".
Такое поведение приводит к потере данных.

Из-за характера предполагаемого приложения I Я не могу создать фрейм на уровне приложения для подтверждения доставки.

# snip from code

class TCPSocketHandler(SocketHandler):
    # init etc ... 

    def connect(self):
        self.socket = socket.socket(socket.AD_INET, socket.SOCK_STREAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
        self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 1)
        self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 1)
        self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 5)
        self.socket.connect((self.dst_host, self.dst_port))
        self.socket.setblocking(0)
        return self.socket

    def _get_socket(self):
        if not self.socket:
            self.socket = self.connect()
        return self.socket

    def send(self, bytes):
        sent = 0
        try:
            socket = self._get_socket()

            # this does not seem to detect sockets in close_wait state
            select.select([], [socket], self.timeout_sec)

            # first call to this after a socket enters close_wait state causes data loss.
            # second call results in broken pipe exception
            sent = socket.send(bytes)
        except socket.error as e:
            err = e.args[0]
            if err == errno.EWOULDBLOCK:
                time.sleep(0.1)
            else:
                self.close()
                time.sleep(0.5)
        return sent

    def close(self):
        self.socket.close()
        self.socket = None

Любая помощь будет принята с благодарностью.

...