From 15545eb6d7ae9f5b70b726a59d236e980efa9a4d Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 6 Jan 2016 23:57:32 +0100 Subject: [PATCH] unix.7: Add example A complete example demonstrating the usage of sockets for local interprocess communication is added. Signed-off-by: Heinrich Schuchardt Signed-off-by: Michael Kerrisk --- man7/unix.7 | 280 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 276 insertions(+), 4 deletions(-) diff --git a/man7/unix.7 b/man7/unix.7 index 2506f4a8d..475f33f1a 100644 --- a/man7/unix.7 +++ b/man7/unix.7 @@ -1,5 +1,6 @@ -.\" This man page is Copyright (C) 1999 Andi Kleen . -.\" and Copyright (C) 2008-2014, Michael Kerrisk +.\" This man page is Copyright (C) 1999 Andi Kleen , +.\" Copyright (C) 2008-2014, Michael Kerrisk , +.\" and Copyright (C) 2016, Heinrich Schuchardt .\" .\" %%%LICENSE_START(VERBATIM_ONE_PARA) .\" and Copyright (C) 2008, 2012 Michael Kerrisk @@ -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 +#include +#include +#include +#include +#include +#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 +#include +#include +#include +#include +#include +#include +#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