On 01/06/2016 11:57 PM, Heinrich Schuchardt wrote: > A complete example demonstrating the usage of sockets for local interprocess > communication is added. > > v2: > Add missing [] for argv. > Use meaningful variable names. > Use AF_UNIX instead of PF_LOCAL. > memset name structure to 0. > Use read, write instead of recv, send. > Thx to Michael for reviewing. Thanks, Heinrich. Applied. (I made a few tweaks afterwards. Nothing major, but let me know if I messed anything up. Cheers, Michael > Signed-off-by: Heinrich Schuchardt <xypron.glpk@xxxxxx> > --- > man7/unix.7 | 280 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 276 insertions(+), 4 deletions(-) > > diff --git a/man7/unix.7 b/man7/unix.7 > index e6e311f..5a4ad63 100644 > --- a/man7/unix.7 > +++ b/man7/unix.7 > @@ -1,5 +1,6 @@ > -.\" This man page is Copyright (C) 1999 Andi Kleen <ak@xxxxxx>. > -.\" and Copyright (C) 2008-2014, Michael Kerrisk <mtk.manpages@xxxxxxxxx> > +.\" This man page is Copyright (C) 1999 Andi Kleen <ak@xxxxxx>, > +.\" Copyright (C) 2008-2014, Michael Kerrisk <mtk.manpages@xxxxxxxxx>, > +.\" and Copyright (C) 2016, Heinrich Schuchardt <xypron.glpk@xxxxxx> > .\" > .\" %%%LICENSE_START(VERBATIM_ONE_PARA) > .\" and Copyright (C) 2008, 2012 Michael Kerrisk <mtk.manpages@xxxxxxxxx> > @@ -618,9 +619,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 > -- Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Linux/UNIX System Programming Training: http://man7.org/training/ -- To unsubscribe from this list: send the line "unsubscribe linux-man" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html