PTHREAD_PROCESS_SHARED
attributepipe()
mkfifo()
socketpair(AF_UNIX, ... )
socket(AF_UNIX, ... )
reliable when used in datagram mode
int socketpair(int domain, int type, int protocol, int sv[2]);
// Returns 0 if OK, -1 on error
Same picture as the one for pipe()
but arrows going both ways:
recv-unix.c
:
static void die(const char *m) { perror(m); exit(1); }
void handle_sigint(int signo) {}
int main(int argc, char **argv)
{
struct sigaction sa;
sa.sa_handler = &handle_sigint;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGINT, &sa, NULL) != 0) {
die("sigaction");
}
if (argc != 2) {
fprintf(stderr, "usage: %s <num-chars>\n", argv[0]);
exit(1);
}
int num_to_recv = atoi(argv[1]);
int fd;
struct sockaddr_un un, clnt_un;
socklen_t len, clnt_len;
char *name = "serv-dom-sock";
assert(strlen(name) < sizeof(un.sun_path));
// create a UNIX domain datagram socket
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
die("socket failed");
// remove the server domain socket file if exists already
unlink(name);
// fill in the server domain socket address structure
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
strcpy(un.sun_path, name);
len = offsetof(struct sockaddr_un, sun_path) + strlen(name);
// bind the server domain socket name to the descriptor
if (bind(fd, (struct sockaddr *)&un, len) < 0)
die("bind failed");
char *buf = malloc(num_to_recv + 1);
char reply[100];
int i = 0, n;
for (;;) {
memset(buf, 0, num_to_recv + 1);
clnt_len = sizeof(clnt_un);
n = recvfrom(fd, buf, num_to_recv, 0,
(struct sockaddr *) &clnt_un, &clnt_len);
if (n < 0) {
if (errno == EINTR)
break;
else
die("recvfrom failed");
}
fprintf(stderr, "\"%s\" received from ", buf);
write(STDERR_FILENO, clnt_un.sun_path,
clnt_len - offsetof(struct sockaddr_un, sun_path));
fprintf(stderr, " (clnt_len:%d), ", clnt_len);
snprintf(reply, sizeof(reply), "[%d](%s)", ++i, buf);
n = sendto(fd, reply, strlen(reply), 0,
(struct sockaddr *) &clnt_un, clnt_len);
if (n != strlen(reply)) {
die("sendto failed");
}
fprintf(stderr, "sent back %d bytes: %s\n", n, reply);
}
// Clean up
fprintf(stderr, "Server shutting down\n");
free(buf);
close(fd);
unlink(name);
}
send-unix.c
:
static void die(const char *m) { perror(m); exit(1); }
int main(int argc, char **argv)
{
if (argc != 3) {
fprintf(stderr, "usage: %s <msg> <num-repeat>\n", argv[0]);
exit(1);
}
const char *msg = argv[1];
int num_repeat = atoi(argv[2]);
int fd;
socklen_t my_len;
struct sockaddr_un my_un;
char my_name[sizeof(my_un.sun_path)];
snprintf(my_name, sizeof(my_name), "clnt-dom-sock.%d", getpid());
// create a UNIX domain datagram socket
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
die("socket failed");
// fill in my own domain socket address structure
memset(&my_un, 0, sizeof(my_un));
my_un.sun_family = AF_UNIX;
strcpy(my_un.sun_path, my_name);
my_len = offsetof(struct sockaddr_un, sun_path) + strlen(my_name);
// bind my own domain sock name to the descriptor
if (bind(fd, (struct sockaddr *)&my_un, my_len) < 0)
die("bind failed");
socklen_t serv_len;
struct sockaddr_un serv_un;
char *serv_name = "serv-dom-sock";
assert(strlen(serv_name) < sizeof(serv_un.sun_path));
// fill in the server's domain socket address structure
memset(&serv_un, 0, sizeof(serv_un));
serv_un.sun_family = AF_UNIX;
strcpy(serv_un.sun_path, serv_name);
serv_len = offsetof(struct sockaddr_un, sun_path) + strlen(serv_name);
int i, n;
// send messages
for (i = 0; i < num_repeat; i++) {
n = sendto(fd, msg, strlen(msg), 0,
(struct sockaddr *) &serv_un, serv_len);
if (n != strlen(msg))
die("sendto failed");
else
fprintf(stderr, "[%d] sent %d bytes: \"%s\"\n", i+1, n, msg);
}
// receive replies
char reply[100];
for (i = 0; i < num_repeat; i++) {
memset(reply, 0, sizeof(reply));
n = recvfrom(fd, reply, sizeof(reply), 0, NULL, NULL);
if (n < 0)
die("recvfrom failed");
else
fprintf(stderr, "%d bytes received: \"%s\"\n", n, reply);
}
// clean up
close(fd);
unlink(my_name);
}
Duplicate a file descriptor across running processes:
Real-world application: a set of worker processes collectively processing activities on a set of long running TCP connections (e.g., WebSocket: first use HTTP request/response to establish a persistent WebSocket connection, then client and server exchange JSON messages freely).
Why not use multiple threads instead of processes? That’s an option for sure, but there are advantages in both approaches; with multiple processes:
Last updated: 2024-10-15