Overview
A Unix domain socket is an IPC method that clients and servers have on a single host. Unix domain sockets do not perform protocol processing, do not need to add or remove network headers, do not require authentication and, do not produce sequential numbers, and do not 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 can use the Socketopair function. The implementation is as follows:
#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 * parameter 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 descriptor as sockfd[0] and sockfd[1] return Back
Unix Domain socket functions
Unix domain sockets have the following differences compared to Internet domain sockets:
- The path name created by bind should have the default access to 0777 and be modified by the current umask value;
- The pathname must be an absolute pathname and avoid using a relative path name. Because its parsing depends on the caller's current working directory, if the server is bound to a relative pathname, then the client and server must be in the same directory 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;
- Calling connect to connect a Unix domain socket involves a permission test equivalent to calling open to access the corresponding pathname in a write-only manner;
- 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. When TCP sockets encounter this situation, TCP listener sockets ignore these incoming SYN connection requests, and TCP clients 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, a path name is not automatically bound to the socket. The UDP socket is automatically bound to a temporary port when it sends data to an unbound UDP socket;
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 SIGALRM signal, the system does not automatically restart */#ifdef sa_interrupt act.sa_flags |= sa_interrupt; #endif} else {/* The remaining signal is set to the system will automatically restart */#ifdef sa_restart act.sa_flags |= sa_restart; #endif}/* Call sigaction function */ 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);}
Resources:
"Unix Network Programming"
"Network Programming" Unix domain sockets