unix.7: Add example

A complete example demonstrating the usage of sockets for local
interprocess communication is added.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
This commit is contained in:
Heinrich Schuchardt 2016-01-06 23:57:32 +01:00 committed by Michael Kerrisk
parent 0d7e8d59bc
commit 15545eb6d7
1 changed files with 276 additions and 4 deletions

View File

@ -1,5 +1,6 @@
.\" This man page is Copyright (C) 1999 Andi Kleen <ak@muc.de>.
.\" and Copyright (C) 2008-2014, Michael Kerrisk <mtk.manpages@gmail.com>
.\" This man page is Copyright (C) 1999 Andi Kleen <ak@muc.de>,
.\" Copyright (C) 2008-2014, Michael Kerrisk <mtk.manpages@gmail.com>,
.\" and Copyright (C) 2016, Heinrich Schuchardt <xypron.glpk@gmx.de>
.\"
.\" %%%LICENSE_START(VERBATIM_ONE_PARA)
.\" and Copyright (C) 2008, 2012 Michael Kerrisk <mtk.manpages@gmail.com>
@ -619,9 +620,280 @@ that the applications that
pathname sockets follow the rules outlined above under
.IR "Pathname sockets" .
.SH EXAMPLE
See
.BR bind (2).
The following code demonstrates the usage of sockets for local interprocess
communication.
It comprises two programs.
The server program waits for a connection from the client program.
The client sends all of its command line arguments.
The server treats them as integers and adds them up.
The client sends the command string END.
The server returns the result.
The client prints the sum of the received integers and exits.
The server waits for the next client to connect.
To stop the server the client is called with the command line argument
DOWN.
.PP
The following output was recorded while running the server in the background
and repeatedly calling the client.
Execution of the server program ended when receiving the DOWN command.
.SS Example output
.in +4n
.nf
$ ./server &
[1] 25887
$ ./client 3 4
Result = 7
$ ./client 11 \-5
Result = 6
$ ./client DOWN
Result = 0
[1]+ Done ./server
$
.fi
.in
.SS Program source
.nf
/*
* File connection.h
*/
#define SOCKET_NAME "/tmp/9Lq7BNBnBycd6nxy.socket"
#define BUFFER_SIZE 12
/*
* File server.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include "connection.h"
int
main(int argc, char *argv[])
{
struct sockaddr_un name;
int down_flag = 0;
int ret;
int connection_socket;
int data_socket;
int result;
char buffer[BUFFER_SIZE];
/*
* In case the program exited inadvertently on the last run
* remove the socket.
*/
unlink(SOCKET_NAME);
/* Create local socket. */
connection_socket = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if (connection_socket == \-1) {
perror("socket");
exit(EXIT_FAILURE);
}
/*
* For portability clear the whole structure, since some implementations
* have additional (nonstandard) fields in the structure.
*/
memset(&name, 0, sizeof(struct sockaddr_un));
/* Bind socket to socket name. */
name.sun_family = AF_UNIX;
strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) \- 1);
ret = bind(connection_socket, (const struct sockaddr *) &name,
sizeof(struct sockaddr_un));
if (ret == \-1) {
perror("bind");
exit(EXIT_FAILURE);
}
/*
* Prepare for accepting connections. The backlog size is set to 20. So
* while one request is being processed other requests can be waiting.
*/
ret = listen(connection_socket, 20);
if (ret == \-1) {
perror("listen");
exit(EXIT_FAILURE);
}
/* This is the main loop for handling connections. */
for (;;) {
/* Wait for incoming connection. */
data_socket = accept(connection_socket, NULL, NULL);
if (ret == \-1) {
perror("accept");
exit(EXIT_FAILURE);
}
result = 0;
for(;;) {
/* Wait for next data packet. */
ret = read(data_socket, buffer, BUFFER_SIZE);
if (ret == \-1) {
perror("recv");
exit(EXIT_FAILURE);
}
/* Ensure buffer is 0\-terminated. */
buffer[BUFFER_SIZE \- 1] = 0;
/* Handle commands. */
if (!strncmp(buffer, "DOWN", BUFFER_SIZE)) {
down_flag = 1;
break;
}
if (!strncmp(buffer, "END", BUFFER_SIZE)) {
break;
}
/* Add received summand. */
result += atoi(buffer);
}
/* Send result. */
sprintf(buffer, "%d", result);
ret = write(data_socket, buffer, BUFFER_SIZE);
if (ret == \-1) {
perror("send");
exit(EXIT_FAILURE);
}
/* Close socket. */
close(data_socket);
/* Quit on DOWN command. */
if (down_flag) {
break;
}
}
close(connection_socket);
/* Unlink the socket. */
unlink(SOCKET_NAME);
exit(EXIT_SUCCESS);
}
/*
* File client.c
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include "connection.h"
int
main(int argc, char *argv[])
{
struct sockaddr_un name;
int i;
int ret;
int data_socket;
char buffer[BUFFER_SIZE];
/* Create local socket. */
data_socket = socket(AF_UNIX, SOCK_SEQPACKET, 0);
if (data_socket == \-1) {
perror("socket");
exit(EXIT_FAILURE);
}
/*
* For portability clear the whole structure, since some implementations
* have additional (nonstandard) fields in the structure.
*/
memset(&name, 0, sizeof(struct sockaddr_un));
/* Connect socket to socket name. */
name.sun_family = AF_UNIX;
strncpy(name.sun_path, SOCKET_NAME, sizeof(name.sun_path) \- 1);
ret = connect (data_socket, (const struct sockaddr *) &name,
sizeof(struct sockaddr_un));
if (ret == \-1) {
fprintf(stderr, "The server is down.\\n");
exit(EXIT_FAILURE);
}
/* Send arguments. */
for (i = 1; i < argc; ++i) {
ret = write(data_socket, argv[i], strlen(argv[i]) + 1);
if (ret == \-1) {
perror("send");
break;
}
}
/* Request result. */
strcpy (buffer, "END");
ret = write(data_socket, buffer, strlen(buffer) + 1);
if (ret == \-1) {
perror("send");
exit(EXIT_FAILURE);
}
/* Receive result. */
ret = read(data_socket, buffer, BUFFER_SIZE);
if (ret == \-1) {
perror("recv");
exit(EXIT_FAILURE);
}
/* Ensure buffer is 0\-terminated. */
buffer[BUFFER_SIZE \- 1] = 0;
printf("Result = %s\\n", buffer);
/* Close socket. */
close(data_socket);
exit(EXIT_SUCCESS);
}
.fi
.PP
For an example of the use of
.BR SCM_RIGHTS
see