linux domain socket

Keywords: socket Unix Linux network

Unix domain socket

One of the ways of communication between processes in Linux is through network socket.

UNIX domain sockets are used to communicate with processes running on the same machine. Although Internet domain sockets can be used for this same purpose, UNIX domain sockets are more efficient. UNIX domain sockets only copy data; they have no protocol processing to perform, no network headers to add or remove, no checksums to calculate, no sequence numbers to generate, and no acknowledgements to send. --------from APUE 17.3

Create socket

 #include <sys/types.h>         
 #include <sys/socket.h>
 int socket(int domain, int type, int protocol);

The API used for socket creation is the same as that used for socket creation, except for different parameters.
The first parameter uses AF ﹣ local or AF ﹣ UNIX, and the other code contains PF ﹣ local or PFUNIX. In the man manual, it is explained that the beginning of P is used by the lower version.
The second parameter can select datagram or streaming data corresponding to socktet? DGAM and socket? Stream
The third parameter is set to 0

Bind socket

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
In apue, it is pointed out that the structure definition of the second parameter of bind is different in different kinds of operating systems.
In < sys / UN. H > of linux 2.4.22:

struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[108]; /* pathname */
};

In other UNIX operating systems, there may be other members in the structure, so the last length parameter needs to be processed using the offset macro in < stddef. H >. This is a very good operation.
#define offsetof(TYPE, MEMBER) ((int)&((TYPE *)0)->MEMBER)
In apue, we also give an example of how to use bind function. (apue is really a divine book!)

#include "apue.h"
#include <sys/socket.h>
#include <sys/un.h>
int
main(void)
{
int fd, size;
struct sockaddr_un un;
un.sun_family = AF_UNIX;
strcpy(un.sun_path, "foo.socket");
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
err_sys("socket failed");
size = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);
if (bind(fd, (struct sockaddr *)&un, size) < 0)
err_sys("bind failed");
printf("UNIX domain socket bound\n");
exit(0);
}

In the SOCKADDR UUN structure, the second parameter is a file path, which will generate a sock file when binding. If the file does not quit, the bind call will fail, which is why the code on the Internet calls the unlink once before bind.
This is also a very good article to learn UNIX domain socket. Introduction to Unix Domain Socket . In the middle, an abstract file path is introduced, which avoids the problem that you need to delete it every time to use it and duplicate it with other paths in the system. It also introduces UNIX domain socket in detail.

listen

#include <sys/types.h> 
#include <sys/socket.h>
int listen(int sockfd, int backlog);
sockfd:
socket File descriptor
backlog:
//Establish number of links and

Or the intact example in apue:

#include "apue.h"
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#define QLEN 10
/*
* Create a server endpoint of a connection.
* Returns fd if all OK, <0 on error.
*/
int
serv_listen(const char *name)
{
    int fd, len, err, rval;
    struct sockaddr_un un;
    /* create a UNIX domain stream socket */
    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
    return(-1);
    unlink(name); /* in case it already exists */
    /* fill in socket address structure */
    memset(&un, 0, sizeof(un));
    un.sun_family = AF_UNIX;
    strcpy(un.sun_path, name);
    len = offsetof(struct sockaddr_un, sun_path) + strlen(name);
    /* bind the name to the descriptor */
    if (bind(fd, (struct sockaddr *)&un, len) < 0) {
    	rval = -2;
    	goto errout;
    }
    if (listen(fd, QLEN) < 0) { /* tell kernel we're a server */
    	rval = -3;
    	goto errout;
    }
    return(fd);
    errout:
    err = errno;
    close(fd);
    errno = err;
    return(rval);
}

Be careful!! The path is that the server and the connection end bind themselves, and then tell the other party their own path.

We don't let the system choose a default address for us, because the server would be unable to distinguish one client from another.Instead, we bind our own address, a step we usually don't take when developing a client program that uses sockets.
//That is to say, under the UNIX domain socket, the connection end also bind s. The reason is not clear. Just remember.

Example of connection end

#include "apue.h"
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#define CLI_PATH "/var/tmp/" /* +5 for pid = 14 chars */
#define CLI_PERM S_IRWXU /* rwx for user only */
/*
* Create a client endpoint and connect to a server.
* Returns fd if all OK, <0 on error.
*/
int
cli_conn(const char *name)
{
    int fd, len, err, rval;
    struct sockaddr_un un;
    /* create a UNIX domain stream socket */
    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
    	return(-1);
    /* fill socket address structure with our address */
    memset(&un, 0, sizeof(un));
    un.sun_family = AF_UNIX;
    sprintf(un.sun_path, "%s%05d", CLI_PATH, getpid());
    len = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);
    unlink(un.sun_path); /* in case it already exists */
    if (bind(fd, (struct sockaddr *)&un, len) < 0) {
    	rval = -2;
    	goto errout;
    }
    if (chmod(un.sun_path, CLI_PERM) < 0) {
        rval = -3;
        goto errout;
    }
    /* fill socket address structure with server's address */
    memset(&un, 0, sizeof(un));
    un.sun_family = AF_UNIX;
    strcpy(un.sun_path, name);
    len = offsetof(struct sockaddr_un, sun_path) + strlen(name);
    if (connect(fd, (struct sockaddr *)&un, len) < 0) {
    	rval = -4;
    	goto errout;
    }
   	return(fd);
   	
    errout:
    	err = errno;
        close(fd);
        errno = err;
        return(rval);
}
Published 7 original articles, praised 0, visited 104
Private letter follow

Posted by Birmingham on Tue, 04 Feb 2020 22:55:17 -0800