Returns a `ZmqPipeEnd` backed by a TCP connection.
        If both ends of the connection are created on the same thread/task, to avoid a deadlock,
        it's necessary to first create both ends, then initialize `'b'` then `'a'`, such as this:

            a = await zmq_tcp_pipe_end(ctx, 'a', port=port, initialize=False)
            b = await zmq_tcp_pipe_end(ctx, 'b', port=a.port)
            await a.initialize()

        In that case, prefer `zmq_tcp_pipe` for creating both ends.

        Side `'a'` will bind a `ROUTER` socket on the given or a random port (host defaults to `*`);
        side `'b'` will connect a `DEALER` socket to the given port (host defaults to `127.0.0.1`).

async def zmq_tcp_pipe_end(ctx, side, *, host=None, port=0, serializer: Optional[Serializer]=None, initialize=True):
        """
        Returns a `ZmqPipeEnd` backed by a TCP connection.
        If both ends of the connection are created on the same thread/task, to avoid a deadlock,
        it's necessary to first create both ends, then initialize `'b'` then `'a'`, such as this:

            a = await zmq_tcp_pipe_end(ctx, 'a', port=port, initialize=False)
            b = await zmq_tcp_pipe_end(ctx, 'b', port=a.port)
            await a.initialize()

        In that case, prefer `zmq_tcp_pipe` for creating both ends.

        Side `'a'` will bind a `ROUTER` socket on the given or a random port (host defaults to `*`);
        side `'b'` will connect a `DEALER` socket to the given port (host defaults to `127.0.0.1`).
        """

        if side == 'a':
            host = host or '*'
            result = ZmqPipeEnd(ctx, zmq.ROUTER, f'tcp://{host}', port=port, bind=True, serializer=serializer)
        elif side == 'b':
            host = host or '127.0.0.1'
            if port == 0:
                raise ValueError("b side requires port argument")
            result = ZmqPipeEnd(ctx, zmq.DEALER, f'tcp://{host}', port=port, serializer=serializer)
        else:
            raise ValueError("side must be 'a' or 'b'")

        if initialize:
            await result.initialize()
        return result