Cogs and Levers A blog full of technical stuff

Unix IPC: Working with Signals

Incoming messages to your process can come in the form of a signal. Signals are standard message packets that the operating system will use to tell your process something about the environment.

This snippet will show you show to setup a signal handler in your program.

/** The signal handler */
void sigint_handler(int sig) {
	/* do something interesting with the sigint here */
}

int main(void) {
	struct sigaction sa;

	/* fill out the signal structure */
	sa.sa_handler = sigint_handler;
	sa.sa_flags   = 0;
	sigemptyset(&sa.sa_mask);

	/* assign it to the appropriate signal */
	sigaction(SIGINT, &sa, NULL);

	/* do other stuff here, sigint will be handled */
}

Further reading

Unix IPC: Unix Sockets

Unix sockets talk locally on the machine. Their operation is very similar to standard socket operations (as they are the same in every way). This snippet will show you a server and client.

int s, s2, t, len;
struct sockaddr_un local, remote;
char str[100];

/* --- as a server --- */

/* create the socket to serve on */
s = socket(AF_UNIX, SOCK_STREAM, 0);
/* fill out the address struct to listen on */
local.sun_family = AF_UNIX;
strcpy(local.sun_path, SOCK_PATH);
unlink(local.sun_path);
len = strlen(local.sun_path) + sizeof(local.sun_family);

/* bind the socket to this name */
bind(s, (struct sockaddr *)&local, len);
/* listen on this socket */
listen(s, 5);
/* accept any incoming connection */
s2 = accept(s, (struct sockaddr *)&remote, &t));
/* receive some data */
n = recv(s2, str, 100, 0);
/* close the client */
close(s2);


/* --- as a client --- */

/* create a socket to connect on */
s = socket(AF_UNIX, SOCK_STREAM, 0);

/* fill out the address struct to connect to */
remote.sun_family = AF_UNIX;
strcpy(remote.sun_path, SOCK_PATH);
len = strlen(remote.sun_path) + sizeof(remote.sun_family);

/* connect on this socket */
connect(s, (struct sockaddr *)&remote, len);

/* send some data */
send(s, str, strlen(str), 0);
/* close the socket */
close(s);

Further reading

Unix IPC: Shared Memory

Shared memory allows multiple processes to view, modify and control shared segments of memory. This snippet will show you how to obtain a pointer to some shared memory and then release the pointer.

key_t key;
int shmid;

/* get an ipc key */
key = ftok("filename", 'R');

/* connect to the segment */
shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT);

/* attach to the segment */
data = shmat(shmid, (void *)0, 0);

/* perform writes and reads on the "data" pointer */

/* detach from the segment */
shmdt(data);

Further reading

Unix IPC: Semaphores

Semaphores can simplify access to shared resources. The following snippet will show you how to create a semaphore set and destroy it.

key_t key;
int semid;

/* get an IPC key */
key = ftok("filename", 'E');
/* create the new semaphore set */
semid = semget(key, 10, 0666 | IPC_CREAT);

/* destroy the semaphore */
semctl(semid, 0, IPC_RMID);

Further reading

Unix IPC: Pipes and FIFOs

This snippet will show you two processes communicating between each other using a pipe.

int pfds[2];
char buf[30];

/* open the pipe */
pipe(pfds);

if (!fork()) {
	/* the child will write to the pipe */
	write(pfds[1], "test", 5);
	exit(0);
} else {
	/* the parent will read from the pipe */
	read(pfds[0], buf, 5);
	wait(NULL);
}

FIFOs are just pipes that have a specific name. In this snippet the name is a constant defined elsewhere called FIFO_NAME.

/* first program writes to the named pipe */
char buffer[20];
int num, fd;

/* create the named pipe */
mknod(FIFO_NAME, S_IFIFO | 0666, 0);
/* open for writing */
fd = open(FIFO_NAME, O_WRONLY);
/* write to the pipe */
write(fd, buffer, strlen(buffer));


/* second program reads from the named pipe */
char buffer[20];
int num, fd;
/* create the named pipe */
mknod(FIFO_NAME, S_IFIFO | 0666, 0);
/* open for reading */
fd = open(FIFO_NAME, O_RDONLY);
/* read from the pipe */
read(fd, s, 20);

Further reading

The mknod system call