* [PATCH] unix.7: add example
@ 2016-01-05 15:17 Heinrich Schuchardt
[not found] ` <1452007033-26166-1-git-send-email-xypron.glpk-Mmb7MZpHnFY@public.gmane.org>
0 siblings, 1 reply; 3+ messages in thread
From: Heinrich Schuchardt @ 2016-01-05 15:17 UTC (permalink / raw)
To: Michael Kerrisk; +Cc: linux-man-u79uwXL29TY76Z2rM5mHXA, Heinrich Schuchardt
A complete example demonstrating the usage of sockets for local interprocess
communication is added.
Signed-off-by: Heinrich Schuchardt <xypron.glpk-Mmb7MZpHnFY@public.gmane.org>
---
man7/unix.7 | 261 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 257 insertions(+), 4 deletions(-)
diff --git a/man7/unix.7 b/man7/unix.7
index e6e311f..dd630ba 100644
--- a/man7/unix.7
+++ b/man7/unix.7
@@ -1,5 +1,6 @@
-.\" This man page is Copyright (C) 1999 Andi Kleen <ak-h9bWGtP8wOw@public.gmane.org>.
-.\" and Copyright (C) 2008-2014, Michael Kerrisk <mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+.\" This man page is Copyright (C) 1999 Andi Kleen <ak-h9bWGtP8wOw@public.gmane.org>,
+.\" Copyright (C) 2008-2014, Michael Kerrisk <mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
+.\" and Copyright (C) 2016, Heinrich Schuchardt <xypron.glpk-Mmb7MZpHnFY@public.gmane.org>
.\"
.\" %%%LICENSE_START(VERBATIM_ONE_PARA)
.\" and Copyright (C) 2008, 2012 Michael Kerrisk <mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@@ -618,9 +619,261 @@ 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 = 0;
+ int ret;
+ int sock;
+ int sock2;
+ int result;
+ char buf[BUFFER_SIZE];
+
+ /*
+ * In case the program exited inadvertently on the last run
+ * remove the socket.
+ */
+
+ unlink(SOCKET_NAME);
+
+ /* Create local socket. */
+
+ sock = socket(PF_LOCAL, SOCK_SEQPACKET, 0);
+ if (sock == \-1) {
+ perror("socket");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Bind socket to socket name. */
+
+ name.sun_family = AF_UNIX;
+ strcpy (name.sun_path, SOCKET_NAME);
+ ret = bind(sock, (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 2. So
+ * while one request is being processed other requests can be waiting.
+ */
+
+ ret = listen(sock, 2);
+ if (ret == \-1) {
+ perror("listen");
+ exit(EXIT_FAILURE);
+ }
+
+ /* This is the main loop for handling connections. */
+
+ for (;;) {
+
+
+ /* Wait for incoming connection. */
+
+ sock2 = accept(sock, NULL, NULL);
+ if (ret == \-1) {
+ perror("accept");
+ exit(EXIT_FAILURE);
+ }
+
+ result = 0;
+ for(;;) {
+
+ /* Wait for next datagram. */
+
+ ret = recv(sock2, buf, BUFFER_SIZE, 0);
+ if (ret == \-1) {
+ perror("recv");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Ensure buffer is 0\-terminated. */
+
+ buf[BUFFER_SIZE \- 1] = 0;
+
+ /* Handle commands. */
+
+ if (!strncmp(buf, "DOWN", BUFFER_SIZE)) {
+ down = 1;
+ break;
+ }
+
+ if (!strncmp(buf, "END", BUFFER_SIZE)) {
+ break;
+ }
+
+ /* Add received summand. */
+ result += atoi(buf);
+ }
+
+ /* Send result. */
+
+ sprintf(buf, "%d", result);
+ ret = send(sock2, buf, BUFFER_SIZE, 0);
+
+ if (ret == \-1) {
+ perror("send");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Close socket. */
+
+ close(sock2);
+
+ /* Quit on DOWN command. */
+
+ if (down) {
+ break;
+ }
+ }
+
+ close(sock);
+
+ /* 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 sock;
+ char buf[BUFFER_SIZE];
+
+ /* Create local socket. */
+
+ sock = socket(PF_LOCAL, SOCK_SEQPACKET, 0);
+ if (sock == \-1) {
+ perror("socket");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Connect socket to socket name. */
+
+ name.sun_family = AF_UNIX;
+ strcpy (name.sun_path, SOCKET_NAME);
+ ret = connect (sock, (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 = send(sock, argv[i], strlen(argv[i]) + 1, 0);
+ if (ret == \-1) {
+ perror("send");
+ break;
+ }
+ }
+
+ /* Request result. */
+
+ strcpy (buf, "END");
+ ret = send(sock, buf, strlen(buf) + 1, 0);
+ if (ret == \-1) {
+ perror("send");
+ exit(EXIT_FAILURE);
+ }
+
+
+ /* Receive result. */
+
+ ret = recv(sock, buf, BUFFER_SIZE, 0);
+ if (ret == \-1) {
+ perror("recv");
+ exit(EXIT_FAILURE);
+ }
+
+ buf[BUFFER_SIZE \- 1] = 0;
+
+ printf("Result = %s\\n", buf);
+
+ /* Close socket. */
+
+ close(sock);
+
+ 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-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related [flat|nested] 3+ messages in thread[parent not found: <1452007033-26166-1-git-send-email-xypron.glpk-Mmb7MZpHnFY@public.gmane.org>]
* Re: [PATCH] unix.7: add example [not found] ` <1452007033-26166-1-git-send-email-xypron.glpk-Mmb7MZpHnFY@public.gmane.org> @ 2016-01-06 14:41 ` Michael Kerrisk (man-pages) [not found] ` <568D277D.5000205-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 0 siblings, 1 reply; 3+ messages in thread From: Michael Kerrisk (man-pages) @ 2016-01-06 14:41 UTC (permalink / raw) To: Heinrich Schuchardt Cc: mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w, linux-man-u79uwXL29TY76Z2rM5mHXA Hello Heinrich, On 01/05/2016 04:17 PM, Heinrich Schuchardt wrote: > A complete example demonstrating the usage of sockets for local interprocess > communication is added. Thanks for doing this. I'm happy to take such a piece for the page, but I think things could be improved a little. > Signed-off-by: Heinrich Schuchardt <xypron.glpk-Mmb7MZpHnFY@public.gmane.org> > --- > man7/unix.7 | 261 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 257 insertions(+), 4 deletions(-) > > diff --git a/man7/unix.7 b/man7/unix.7 > index e6e311f..dd630ba 100644 > --- a/man7/unix.7 > +++ b/man7/unix.7 > @@ -1,5 +1,6 @@ > -.\" This man page is Copyright (C) 1999 Andi Kleen <ak-h9bWGtP8wOw@public.gmane.org>. > -.\" and Copyright (C) 2008-2014, Michael Kerrisk <mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > +.\" This man page is Copyright (C) 1999 Andi Kleen <ak-h9bWGtP8wOw@public.gmane.org>, > +.\" Copyright (C) 2008-2014, Michael Kerrisk <mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>, > +.\" and Copyright (C) 2016, Heinrich Schuchardt <xypron.glpk-Mmb7MZpHnFY@public.gmane.org> > .\" > .\" %%%LICENSE_START(VERBATIM_ONE_PARA) > .\" and Copyright (C) 2008, 2012 Michael Kerrisk <mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > @@ -618,9 +619,261 @@ 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) char *argv[] > +{ > + struct sockaddr_un name; > + int down = 0; > + int ret; > + int sock; > + int sock2; I think these names could be more meaningful. One is the listening socket, the other is the connected socket. So, how about lfd cfd or listen_sock conn_sock or lsock csock or something else suitable > + int result; > + char buf[BUFFER_SIZE]; > + > + /* > + * In case the program exited inadvertently on the last run > + * remove the socket. > + */ > + > + unlink(SOCKET_NAME); > + > + /* Create local socket. */ > + > + sock = socket(PF_LOCAL, SOCK_SEQPACKET, 0); s/PF_LOCAL/AF_UNIX/ (POSIX does not specify the PF_* constants; they're historical baggage, and for my money, AF_UNIX beats AF_LOCAL.) > + if (sock == \-1) { > + perror("socket"); > + exit(EXIT_FAILURE); > + } > + > + /* Bind socket to socket name. */ > + > + name.sun_family = AF_UNIX; > + strcpy (name.sun_path, SOCKET_NAME); make this: memset(name, 0, sizeof(struct sockaddr_un)); strncpy (name.sun_path, SOCKET_NAME, sizeof(name.sun_path) \- 1); memset() really is needed, for portability, since some implementations have additional (nonstandard) fields in the structure. (I won't insist on strncpy(), but I think it's marginally better.) > + ret = bind(sock, (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 2. So > + * while one request is being processed other requests can be waiting. > + */ > + > + ret = listen(sock, 2); 2 is unusually low. Why that number? > + if (ret == \-1) { > + perror("listen"); > + exit(EXIT_FAILURE); > + } > + > + /* This is the main loop for handling connections. */ > + > + for (;;) { > + > + > + /* Wait for incoming connection. */ > + > + sock2 = accept(sock, NULL, NULL); > + if (ret == \-1) { > + perror("accept"); > + exit(EXIT_FAILURE); > + } > + > + result = 0; > + for(;;) { > + > + /* Wait for next datagram. */ > + > + ret = recv(sock2, buf, BUFFER_SIZE, 0); > + if (ret == \-1) { > + perror("recv"); > + exit(EXIT_FAILURE); > + } Maybe it's simpler just to use read() here, since the 'flags' argument is unused. > + > + /* Ensure buffer is 0\-terminated. */ > + > + buf[BUFFER_SIZE \- 1] = 0; > + > + /* Handle commands. */ > + > + if (!strncmp(buf, "DOWN", BUFFER_SIZE)) { > + down = 1; > + break; > + } > + > + if (!strncmp(buf, "END", BUFFER_SIZE)) { > + break; > + } > + > + /* Add received summand. */ > > + result += atoi(buf); > + } > + > + /* Send result. */ > + > + sprintf(buf, "%d", result); > + ret = send(sock2, buf, BUFFER_SIZE, 0); > + > + if (ret == \-1) { > + perror("send"); > + exit(EXIT_FAILURE); > + } Maybe it's simpler just to use read() here, since the 'flags' argument is unused. > + /* Close socket. */ > + > + close(sock2); > + > + /* Quit on DOWN command. */ > + > + if (down) { > + break; > + } > + } > + > + close(sock); > + > + /* 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 sock; > + char buf[BUFFER_SIZE]; > + > + /* Create local socket. */ > + > + sock = socket(PF_LOCAL, SOCK_SEQPACKET, 0); PF_LOCAL ==> AF_UNIX > + if (sock == \-1) { > + perror("socket"); > + exit(EXIT_FAILURE); > + } > + > + /* Connect socket to socket name. */ > + > + name.sun_family = AF_UNIX; > + strcpy (name.sun_path, SOCKET_NAME); See comments above re memset() and strncpy(). > + ret = connect (sock, (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 = send(sock, argv[i], strlen(argv[i]) + 1, 0); > + if (ret == \-1) { > + perror("send"); > + break; > + } write() instead of send()? > + } > + > + /* Request result. */ > + > + strcpy (buf, "END"); > + ret = send(sock, buf, strlen(buf) + 1, 0); > + if (ret == \-1) { > + perror("send"); > + exit(EXIT_FAILURE); > + } > + > + > + /* Receive result. */ > + > + ret = recv(sock, buf, BUFFER_SIZE, 0); read() instead of recv() > + if (ret == \-1) { > + perror("recv"); > + exit(EXIT_FAILURE); > + } > + > + buf[BUFFER_SIZE \- 1] = 0; > + > + printf("Result = %s\\n", buf); > + > + /* Close socket. */ > + > + close(sock); > + > + exit(EXIT_SUCCESS); > +} > +.fi > +.PP > For an example of the use of > .BR SCM_RIGHTS > see Cheers, Michael -- 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-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 3+ messages in thread
[parent not found: <568D277D.5000205-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [PATCH] unix.7: add example [not found] ` <568D277D.5000205-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2016-01-06 21:06 ` Heinrich Schuchardt 0 siblings, 0 replies; 3+ messages in thread From: Heinrich Schuchardt @ 2016-01-06 21:06 UTC (permalink / raw) To: Michael Kerrisk (man-pages); +Cc: linux-man-u79uwXL29TY76Z2rM5mHXA On 01/06/2016 03:41 PM, Michael Kerrisk (man-pages) wrote: > Hello Heinrich, > > On 01/05/2016 04:17 PM, Heinrich Schuchardt wrote: >> A complete example demonstrating the usage of sockets for local interprocess >> communication is added. > > Thanks for doing this. I'm happy to take such a piece for the page, but > I think things could be improved a little. > Hello Michael, thank you for reviewing. I will update the patch. http://pubs.opengroup.org/onlinepubs/009695399/functions/recv.html has the following sentence: The recv() function is equivalent to recvfrom() with a zero address_len argument, and to read() if no flags are used. Shouldn't we add this information to recv.2? Send.2 documents the equivalences. Best regards Heinrich -- To unsubscribe from this list: send the line "unsubscribe linux-man" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2016-01-06 21:06 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-01-05 15:17 [PATCH] unix.7: add example Heinrich Schuchardt
[not found] ` <1452007033-26166-1-git-send-email-xypron.glpk-Mmb7MZpHnFY@public.gmane.org>
2016-01-06 14:41 ` Michael Kerrisk (man-pages)
[not found] ` <568D277D.5000205-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2016-01-06 21:06 ` Heinrich Schuchardt
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).