Overview
Today we explain a content in network programming--unix local socket.
Found that a lot of people do not know or do not understand the concept of Unix local sockets, it is no wonder that the socket API is originally for the network communication between the host design, and this network socket also supports the single host of interprocess communication, of course, it still needs IP Address and port number (via loopback address 127.0.0.1). UNIX local sockets, in fact, is a method dedicated to local (that is, a single host) of network traffic, which uses the same API as the network socket API we used before.
The UNIX local sockets described in this article develop an IPC mechanism in the framework of the socket, UNIX domain sockets, or UNIX, or UNIX, local sockets. Compared to the network socket and Ipc,unix local socket has its own characteristics and advantages, let's take a look at the following.
While Unix local sockets are often taught in network programming in many textbooks, this communication is more akin to the way we learned about IPC (interprocess communication), such as The Nameless pipe (pipe), the famous pipe (MKFIFO). However, UNIX domain sockets provide more control, such as TCP (a byte-stream socket) provides the ability to wait for connections, and UDP (datagram sockets) provides frame synchronization and Full-duplex (for example, using Socketpair The two descriptors in the created stream pipeline are both readable and writable.
TCP and UDP
First, we review the server and client side of the TCP and UDP sockets, from the creation of the socket, to the connection, to the data transfer, to the entire process of closing the socket.
TCP is a connection-oriented byte-stream socket, so the server needs to be converted to a passive socket via listen (), waiting for the connection via accept ().
Figure 1. TCP client/server communication process
For UDP, it is simpler, because it is a connectionless datagram socket, and in fact, the concept of client/server side is also weakened.
Figure 2. UDP Communication Process
Unix Local Socket API
As we mentioned earlier, the API used by Unix domain sockets is actually the same as the socket API we used to use, and for TCP and UDP, the workflow is exactly the same as the network socket above.
So, let's take a look at how to create and use our Unix local sockets through these APIs, and what the difference is between them, and then experience it through a simple sample program.
Creating Sockets
The first is the creation of the socket. Also use the socket () function.
But its first argument domain is no longer af_inet or pf_inet, but Af_unix, which represents the UNIX domain local socket. What about the af_local? This is actually a historical cause, our theme is "Unix local sockets" or "UNIX domain sockets", but we actually use Linux, right. In fact, in order to eliminate its reliance on the UNIX operating system, the POSIX standard has already turned Af_unix into af_local, but nevertheless, we are still accustomed to using the "Unix domain" title, so we recommend that you use af_local.
The second argument, like an Internet domain socket, can be sock_stream, Sock_dgram, and Sock_raw, but in fact, it's almost never seen using the original socket. So generally Unix provides two types of sockets, that is, a byte-stream socket (similar to TCP) and a datagram socket (similar to UDP).
The third argument Protocol, obviously, because the second parameter type is not the original socket, so Protocol generally fill in 0.
Binding Address
After you create the socket, the next step is to bind the address through the bind () function, but for Unix local sockets, the bound address is not the original IP address + port number, but a valid path.
The address structure of the local socket sockaddr_un suffix is _un, representing Unix, not the original sockaddr_in (Internet). Let's take a look at what is included in the address structure of this UNIX domain socket:
The address structure of a Unix local socket contains two members, where sun_family represents the protocol family, af_local or Af_unix can be filled, and Sun_path represents a path name.
It's clear from here that the UNIX domain socket differs from the original network socket, and the protocol address used to identify clients and servers in the UNIX domain is the pathname in the normal file system, and this file is called a socket file .
The point to emphasize here is that the path name associated with a Unix local socket should be an absolute pathname , not a relative path name. Why, then? Because resolving a relative path relies on the caller's current working directory, that is, if the server binds a relative pathname, the client must also be able to successfully invoke the Connect (connection) or sendto (send) function in the same directory as the service side. Obviously, this can cause an exception to the program, so it is advisable to use an absolute pathname.
This pathname, in fact, is divided into two kinds, one is the normal path name mentioned above, the other is the abstract path name. The normal path name is a normal string, that is, the Sun_path field ends with a null character (' "). and the abstract pathname, the first byte of the Sun_path field needs to be set to NULL (' \ 0 '), so be careful when calculating the length of an abstract pathname, otherwise you may get an exception when parsing an abstract pathname, because the abstract pathname is not resolved to the first NULL as the normal pathname is parsed.
The advantage of using abstract pathname is that because no more files are created in the file system, for abstract pathname, there is no need to worry about name conflicts with files that already exist in the file system, or to delete the attached file after using the socket. This abstract name is automatically deleted when the socket is closed.
Other APIs
Other APIs, such as listen (), accept (), connect (), and read (), write (), recv (), Send (), Recvfrom (), SendTo (), recvmsg (), Sendmsg (), the use of the same as the network socket, mainly the address structure to pay attention to.
In addition, these APIs are often used in the use of Unix local sockets:
(1) Used to create a local socket similar to the nameless pipe (pipe)
int socketpair (int domain, int type, int protocol, int sv[2]);
(2) When this Unix domain socket is no longer needed, delete the file that corresponds to the path name
int unlink (const char *pathname);
int remove (const char *pathname);
Note that if you are an abstract pathname, you do not need to manually delete the corresponding socket file after you use the local socket, because the kernel automatically deletes the abstract name when the local socket is closed.
(3) Obtaining address information for local sockets
int getsockname (int sockfd, struct sockaddr *addr, socklen_t *addrlen);
Sample
TCP ( byte-throttle socket)
In this example, we use the absolute path name "/TMP/UNIX.STR" to implement a byte stream local socket, the server receives the data, the client sends the data.
"Unixstr_serv.c"
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <
sys/socket.h> #include <sys/un.h> #define UNIXSTR_PATH "/TMP/UNIX.STR" #define LISTENQ 5 #define BUFFER_SIZE 256
int main (void) {int listenfd, CONNFD;
Socklen_t Len;
struct Sockaddr_un servaddr, cliaddr;
if ( -1 = = (LISTENFD = socket (af_local, sock_stream, 0)) {perror ("socket");
Exit (Exit_failure);
} unlink (Unixstr_path);
Bzero (&servaddr, sizeof (SERVADDR));
servaddr.sun_family = af_local;
strcpy (Servaddr.sun_path, Unixstr_path);
if ( -1 = = Bind (LISTENFD, (struct sockaddr *) &servaddr, sizeof (SERVADDR))) {perror ("bind");
Exit (Exit_failure);
} Listen (LISTENFD, Listenq);
len = sizeof (CLIADDR);
if ( -1 = = (CONNFD = Accept (LISTENFD, (struct sockaddr *) &cliaddr, &len))) {perror ("accept");
Exit (Exit_failure); } Char Buf[buFfer_size];
while (1) {bzero (buf, sizeof (BUF));
if (read (CONNFD, buf, buffer_size) = = 0) break;
printf ("Receive:%s", buf);
Close (LISTENFD);
Close (CONNFD);
Unlink (Unixstr_path);
return 0;
}
"Unixstr_cli.c"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h >
#include <sys/socket.h>
#include <sys/un.h>
#define Unixstr_path "/tmp/unix.str"
#define LISTENQ 5
#define BUFFER_SIZE 256
int main (void)
{
int sockfd;
struct Sockaddr_un servaddr;
SOCKFD = socket (af_local, sock_stream, 0);
Bzero (&servaddr, sizeof (SERVADDR));
servaddr.sun_family = af_local;
strcpy (Servaddr.sun_path, unixstr_path);
Connect (SOCKFD, (struct sockaddr *) &servaddr, sizeof (SERVADDR));
Char buf[buffer_size];
while (1)
{
bzero (buf, sizeof (buffer_size));
printf (">>");
if (Fgets (buf, buffer_size, stdin) = = NULL)
{break
;
}
Write (SOCKFD, buf, strlen (BUF));
}
Close (SOCKFD);
return 0;
}
Interested children's shoes can be compiled, executed, to see the effect of the operation, let's take a look at this document/TMP/UNIX.STR.
rudy@ubuntu12:/tmp$ ls-l unix.str
srwxrwxr-x 1 Rudy Rudy 0 October 11:58 Unix.str
Obviously, the file type is "S", which represents the socket file, which is the S_ifsock type.
UDP (datagram socket)
Similar to the above TCP example, we use the absolute pathname "/TMP/UNIX.DG" to implement a datagram's local socket, one end receives the data, the other end sends the data.
"Unixdg_serv.c"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h >
#include <sys/socket.h>
#include <sys/un.h>
#define Unixdg_path "/TMP/UNIX.DG"
# Define BUFFER_SIZE 256
int main (void)
{
int sockfd;
struct Sockaddr_un servaddr, cliaddr;
SOCKFD = socket (af_local, SOCK_DGRAM, 0);
Unlink (Unixdg_path);
Bzero (&servaddr, sizeof (SERVADDR));
servaddr.sun_family = af_local;
strcpy (Servaddr.sun_path, unixdg_path);
Bind (SOCKFD, (struct sockaddr *) &servaddr, sizeof (SERVADDR));
socklen_t len = sizeof (CLIADDR);
Char buf[buffer_size];
while (1)
{
bzero (buf, buffer_size);
if (0 = = Recvfrom (SOCKFD, buf, Buffer_size, 0, (struct sockaddr *) &cliaddr, &len))
{break
;
}
printf ("Recvfrom:%s", buf);
}
Close (SOCKFD);
Unlink (Unixdg_path);
return 0;
}
"Unixdg_cli.c"
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <
sys/socket.h> #include <sys/un.h> #define UNIXDG_PATH "/TMP/UNIX.DG" #define BUFFER_SIZE 256 int main (void) {
int sockfd;
struct Sockaddr_un servaddr, cliaddr;
Socklen_t Len;
SOCKFD = socket (af_local, SOCK_DGRAM, 0);
/* Local Address * * bzero (&cliaddr, sizeof (CLIADDR));
cliaddr.sun_family = af_local;
strcpy (Cliaddr.sun_path, Unixdg_path);
Bind (SOCKFD, (struct sockaddr *) &cliaddr, sizeof (CLIADDR));
/* Remote Address * * bzero (&servaddr, sizeof (SERVADDR));
servaddr.sun_family = af_local;
strcpy (Servaddr.sun_path, Unixdg_path);
len = sizeof (SERVADDR);
Char Buf[buffer_size];
while (1) {bzero (buf, buffer_size);
printf (">>");
if (Fgets (buf, buffer_size, stdin) = = NULL) {break; SendTo (SOCKFD, buf, strlen (BUF), 0,(struct sockaddr *) &servaddr, Len);
Close (SOCKFD);
return 0;
}
It is important to note that, unlike network sockets, for UDP clients of Unix domain sockets, you must bind a path name to a UDP socket so that the UDP server has the destination to send the answer to.
Summary
With the simple example above, we can see that Unix local sockets and Internet sockets use the same API but differ in usage, as compared to IPC (such as pipes, message queues, shared memory, and so on). We can simply think of Unix local sockets as a mixture of sockets and pipes.
It can be said that the advantage of the UNIX local socket is that the API it uses is almost equivalent to the API used by the network socket (client/server), but the UNIX local character throttle socket has a performance advantage over TCP on the same host as both the client and service side. In a single host, it is advantageous to use Unix domain sockets instead of Internet domain sockets.
Finally, summarize:
(1) The Socket can also be used for local communication.
(2) Local protocol af_local is used when creating sockets.
(3) is divided into streaming socket (SOCK_STREAM) and datagram Sockets (SOCK_DGRAM).
(4) compared with other interprocess communication methods, Unix local sockets are easy to use and have high efficiency. Because it does not need to go through the network protocol stack, does not need to package the unpacking, does not need to compute the checksum, does not need to maintain the serial number and the reply and so on, only then copies the application layer data from one process to the other process ...
(5) often used for front and rear process communication, such as X Window.
(6) In addition, Unix local sockets can be used to pass a file descriptor, pass user credentials, and other scenarios.