Well, jupyter_console itself is a frontend/CLI, it starts another process (ipykernel) and communicate with it using ZMQ. IPykernel itself use IPython as a library to execute code.
It might be easier to send code to an ipykernel started with jupyter_console, as it already has an eventloop and is listening to sockets, that trying to talk to an IPython. Plus using ZMQ you'll have richer messages than just text.