Overview
A Unix domain socket is an IPC method for client and server on a single host. Unix domain sockets do not run protocol processing, do not need to join or delete the network header, do not need to verify and, do not generate sequential numbers, no need to send acknowledgement messages, more efficient than Internet domain sockets. UNIX domain sockets provide a byte stream (similar to TCP) and datagram (similar to UDP) interfaces, and the UNIX domain datagram service is reliable, without losing messages or passing errors. A UNIX domain socket is a mixture of sockets and pipelines.
Unix Domain Socket Programming
Address structure:
struct sockaddr_un{sa_family_t sun_family;/* Af_unix */char sun_path[108];/* pathname */};
The path name stored in the Sun_path array must end with a null character. The following is a program that binds a path name to a Unix domain socket implementation:
/* Create a UNIX domain socket and bind a path name */#include <sys/socket.h> #include <sys/un.h> #include <string.h># Include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <stddef.h>extern void err_ SYS (const char *, ...); extern void Err_quit (const char *, ...); int main (int argc, char **argv) {int sockfd, size; Socklen_t Len; struct Sockaddr_un addr1, ADDR2; if (argc! = 2) err_quit ("Usage:%s <pathname>", argv[0]); Bzero (&ADDR1, sizeof (ADDR1)); addr1.sun_family = Af_unix; strncpy (Addr1.sun_path, argv[1], sizeof (Addr1.sun_path)-1); /* Create a UNIX domain socket */if ((SOCKFD = socket (Af_unix, sock_stream, 0)) < 0) Err_sys ("Socket error"); /* If the pathname exists in the file system, bind will go wrong, so call unlink to remove the path name to bind, prevent bind error/unlink (argv[1]); /* Bind the path name bind to the socket */size = Offsetof (struct Sockaddr_un, Sun_path) + strlen (Addr1.sun_path); if (Bind (SOCKFD, (struct sockaddr *) &addr1, size) < 0) Err_sys ("Bind error"); /* Show the bound pathName */len = sizeof (ADDR2); GetSockName (SOCKFD, (struct sockaddr *) &ADDR2, &len); printf ("Bound name =%s, returned len =%d\n", Addr2.sun_path, Len); Exit (0);}
$./main/tmp/sockbound name =/tmp/sock, returned len = 12/* The following prompt appears when the pathname exists and does not use the Unlink function */$./main/tmp/sockbind Error: Address already in use
In order to create a pair of non-named, interconnected Unxi domain sockets, the user is able to use the Socketopair function. In fact, for example, the following:
#include <sys/socket.h>int socketpair (int domain, int type, int protocol, int sockfd[2]);/* Return value: Returns 0 if successful, 1 *//if an error occurs * Description * The domain must be af_local or af_unix,protocol must be 0,type can be sock_stream or SOCK_DGRAM, the newly created two socket descriptive descriptor as sockfd[0] and sockfd[1 Returns
Unix Domain socket functions
Unix domain sockets have the following differences compared to Internet domain sockets:
- The path name created by bind should have a default access of 0777 and be changed according to the current umask value;
- The pathname must be an absolute pathname and avoid using a relative path name. Because its parsing relies on the caller's current working folder, if the server is bound to a relative pathname, then the client and server must be in the same folder for the ability to work properly;
- The pathname specified in the Connect call must be a path name that is currently bound on an open Unix domain socket, and the socket type must be the same;
- Call Connect connect a Unix domain socket involves a permission test equivalent to calling open to access the corresponding path name only by writing;
- Unix domain byte-stream sockets are similar to TCP sockets: They all provide a byte-stream interface with no record boundary for the process;
- In Unix domain byte-stream sockets, a econnrefused error is returned immediately if the queue for the listening socket is found to be full when connect is called. In the case of TCP sockets, the TCP listener ignores these incoming SYN connection requests, and the TCP client will re-send several SYN message segments;
- Unix Domain datagram sockets are similar to UDP sockets: they all provide an unreliable datagram that preserves record boundaries;
- When sending data for a Unix socket with an unbound pathname, it does not voluntarily bind a path name to the socket itself. UDP sockets, when sending data to an unbound UDP socket, will voluntarily bind it to a temporary port;
Unix Domain byte stream programming
Server program:
#include <sys/socket.h> #include <sys/wait.h> #include <sys/un.h> #include <string.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <stddef.h> #include <signal.h > #include <errno.h> #define qlen 1024typedef void Sigfunc (int), extern void Err_sys (const char *, ...); extern void Err_quit (const char *, ...); extern void Str_echo (int), static sigfunc *mysignal (int signo, Sigfunc *func), static sigfunc *m_signal (int signo, Sigfunc * func), static void sig_chld (int), int main (int argc, char **argv) {int sockfd, CONNDFD, size; Socklen_t Len; pid_t Childpid; struct Sockaddr_un cliaddr, servaddr; if (argc! = 2) err_quit ("Usage:%s <pathname>", argv[0]); Bzero (&servaddr, sizeof (SERVADDR)); servaddr.sun_family = Af_unix; strcpy (Servaddr.sun_path, argv[1]); /* Create a UNIX domain socket */if ((SOCKFD = socket (Af_unix, sock_stream, 0)) < 0) Err_sys ("Socket error"); /* If the pathname is already present in the file system, bind will be faulted;So call unlink first to remove the path name to bind, to prevent bind error/unlink (argv[1]); /* Bind the path name bind to the socket */size = Offsetof (struct Sockaddr_un, Sun_path) + strlen (Servaddr.sun_path); if (Bind (SOCKFD, (struct sockaddr *) &servaddr, size) < 0) Err_sys ("Bind error"); /* Listen socket */if (Listen (SOCKFD, Qlen) < 0) {close (SOCKFD); Err_sys ("Listen error"); }/* Signal processing */mysignal (SIGCHLD, SIG_CHLD); for (;;) {len = sizeof (CLIADDR); if (CONNDFD = Accept (SOCKFD, (struct sockaddr *) &cliaddr, &len)) < 0) {if (errno = = eintr) Continue else Err_sys ("Accept error"); }} if ((Childpid = fork ()) = = 0) {close (SOCKFD); Str_echo (CONNDFD); Exit (0); } close (CONNDFD);} void sig_chld (int signo) {pid_t pid; int stat; while (PID = Waitpid ( -1, &stat, Wnohang)) > 0) printf ("Child%d terminated\n", PID); return;} Static Sigfunc *mysignAl (int signo, Sigfunc *func) {Sigfunc *sigfunc; if (Sigfunc = M_signal (Signo, func)) = = Sig_err) Err_sys ("Signal error"); return (SIGFUNC);} static Sigfunc *m_signal (int signo, sigfunc *func) {struct Sigaction Act, oact; /* Set Signal processing function */Act.sa_handler = func; /* Initialize the signal set */Sigemptyset (&act.sa_mask); act.sa_flags = 0; if (Signo = = SIGALRM) {/* If the SIGALRM signal, the system does not voluntarily restart */#ifdef sa_interrupt act.sa_flags |= sa_interrupt; #endif } else {/* The remaining signal is set to the system will voluntarily reboot */#ifdef sa_restart act.sa_flags |= sa_restart; #endif}/* Call Sigaction Letter Number */if (sigaction (Signo, &act, &oact) < 0) return (SIG_ERR); return (Oact.sa_handler);}
Client program:
#include <sys/socket.h> #include <sys/un.h> #include <string.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <errno.h>extern void Err_sys (const char *, ...); extern void Err_quit (const char *, ...); extern void Str_cli (FILE *, int); Intmain (int argc, char **argv) {intsockfd;struct sockaddr_unservaddr; if (argc! = 2) err_quit ("Usage:%s <pathname>", argv[0]); if (SOCKFD = socket (Af_unix, sock_stream, 0)) < 0)
err_sys ("socket error"); Bzero (&servaddr, sizeof (SERVADDR)); servaddr.sun_family = af_unix;strcpy ( Servaddr.sun_path, argv[1]); int err;err = connect (sockfd, (struct sockaddr *) &servaddr, sizeof (SERVADDR)), if (Err < 0) err_sys ("Connect ER Ror "); Str_cli (stdin, SOCKFD);/* Do it All */exit (0);}
References:
"Unix Network Programming"
"Network Programming" Unix domain sockets