def create_sockets(self):
        """create zmq sockets"""

        ports = self.ports

        context = zmq.Context()
        poller = zmq.Poller()

        # Socket to handle init data
        rep = context.socket(zmq.REP)
        # this was inconsequent: here REQ is for the client, we reply with REP.
        # PULL and PUB is seen from here, not from the client.
        # Is now renamed to PUSH and SUB: everything is seen from outside.
        if "REQ" in ports:
            rep.bind(
                "tcp://*:{port}".format(port=ports["REQ"])
            )
        else:
            ports["REQ"] = rep.bind_to_random_port(
                "tcp://*"
            )

        pull = context.socket(zmq.PULL)
        if "PUSH" in ports:
            pull.bind(
                "tcp://*:{port}".format(port=ports["PUSH"])
            )
        else:
            ports["PUSH"] = pull.bind_to_random_port(
                "tcp://*"
            )

        # for sending model messages
        pub = context.socket(zmq.PUB)
        if "SUB" in ports:
            pub.bind(
                "tcp://*:{port}".format(port=ports["SUB"])
            )
        else:
            ports["SUB"] = pub.bind_to_random_port(
                "tcp://*"
            )

        poller.register(rep, zmq.POLLIN)
        poller.register(pull, zmq.POLLIN)

        sockets = dict(
            poller=poller,
            rep=rep,
            pull=pull,
            pub=pub
        )
        return sockets