mirror of https://github.com/mkerrisk/man-pages
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:
parent
0d7e8d59bc
commit
15545eb6d7
280
man7/unix.7
280
man7/unix.7
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue