- They're scoped within the program (no global signal handler that you need to trampoline out of)
- The number of IPC channels you can create is effectively unbounded (not really true, but much less limiting than signals). If another process or part of the program needs IPC you can just open a new channel without breaking code or invariants relied upon by any other IPC channels.
- Reads/writes can be handled asynchronously without interrupting any thread in the program.
- You can use them across the network (AF_INET), VMs (AF_VSOCK), or restrict locally (AF_UNIX)
- Unix sockets can be used to send file descriptors around, even if they're opened by a child after forking. That includes using Unix sockets to send the file descriptor of other sockets (eg program 1 is talking to program 2 on the same machine and program 2 opens an IPC channel with program 3 and wants to send it back to program 1).
I feel like just because you can use signals for IPC doesn't mean you should.