[PATCH 1/1 v2] unix.7: add example

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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.

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
-- 
2.1.4

--
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



[Index of Archives]     [Kernel Documentation]     [Netdev]     [Linux Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux