Local socket (domain) communication

socket IPC

   socket API was originally designed for network communication, but later developed an IPC mechanism based on the socket framework, namely UNIX Domain Socket. Although the network socket can also be used for interprocess communication of the same host (through loopback address 127.0.0.1), but UNIX Domain Socket is more efficient for IPC: it does not need to go through the network protocol stack, pack and unpack, calculate checksum, maintain sequence number and response, but just copy application layer data from one process to another. This is because IPC mechanism is essentially reliable communication, while network protocol is unreliable communication Designed. UNIX domain sockets also provide stream oriented and packet oriented API interfaces, similar to TCP and UDP, but message oriented UNIX domain sockets are also reliable, and messages will not be lost or out of order.

   UNIX Domain Socket is full duplex and has rich API interface semantics. It has obvious advantages over other IPC mechanisms. At present, it has become the most widely used IPC mechanism. For example, the communication between X Window server and GUI program is through UNIXDomain Socket.

  the most obvious difference between UNIX Domain Socket and network socket programming is that the address format is different. The structure SOCKADDR is used_ UN means that the socket address of network programming is the IP address plus the end slogan, while the address of UNIX Domain Socket is the path of a socket type file in the file system. This socket file is created by calling bind(). If the file already exists when calling bind(), the bind() error is returned.

Compare network sockets

int socket(int domain, int type, int protocol);

Parameters:

  domain: AF_UNIX, AF_LOCAL

  type: SOCK_STREAM,SOCK_DGRAM

Socket address structure:

struct sockaddr_in 
{
	__kernel_sa_family_t **sin_family**; 	/* Address family */  Address structure type
	__be16 **sin_port**;					/* Port number */		Port number
	struct in_addr **sin_addr**;		   /* Internet address */	IP address
};

struct sockaddr_un 
{
	__kernel_sa_family_t **sun_family**; 	/* AF_UNIX */	Address structure type
	char **sun_path**[UNIX_PATH_MAX]; 		/* pathname */	socket file name(Including path)
};
network sockets local sockets
Function parametersdomain: AF_INET
type: SOCK_STREAM,SOCK_DGRAM
domain: AF_UNIX, AF_LOCAL
type: SOCK_STREAM,SOCK_DGRAM
Address structuresockaddr_insockaddr_un
Address structure initializationstruct sockaddr_in srv_addr
srv_addr.sin_family=AF_INET
srv_addr. sin port=htons(8888);
srv_addr.sinaddr.s_addr=htonl(INADDR_ANY)
bind(fd(structsockaddr*)&srv_addr,sizeof(srv_addr))
struct sockaddr_un srv_addr
srv_addr.sun_family=AF_UNIX/ AF_LOCAL
strcpy(srv_addr. sun path,"srv. socket")
len=brtsetof(struct sockaddr un, sium path+strlen("srv. socket")
bind(fd,(struct sockaddr *)& srv_addr,1en)
bind functionCall the bind functionIf the bind function is called successfully, a socket will be created to ensure successful bind. Before that, use the unlink function
clientDependency "implicit binding"The client cannot rely on "implicit binding" to create and initialize two address structures in the process of establishing communication.

Local socket for communication

Communication flow

Server program

#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/un.h>
#include <ctype.h>
#include <arpa/inet.h>
#include "wrap.h"
using namespace std;

//Define a port number
#define SERVER_PORT  9527
//#define BUFSIZ _IO_BUFSIZ
#define SERVER_ADDR "server.socket"

int main (int argc,char *argv[])
{
   
    int link_fd=0;//The file descriptor used to establish the connection
    int cfd=0;//Used to communicate with the server

    int ret,len,size;
    char buf[BUFSIZ];//4096
    //Create socket
    link_fd=Socket(AF_UNIX,SOCK_STREAM,0);
    //Check the return value to determine whether the creation is successful
    if(link_fd==-1)
    {
        sys_err("socket error");
    }
    //Create initialization members of server and client structures
    struct sockaddr_un server_addr,client_addr;//Import header file #include < netinet / in h>
    //socklen_t client_addrlen;

    bzero(&server_addr,sizeof(server_addr));
    server_addr.sun_family=AF_UNIX;
    strcpy(server_addr.sun_path,SERVER_ADDR);
   
    //Find the length of (local socket) binding address structure (2 bytes) and solve it by macro function
    len =offsetof(struct sockaddr_un,sun_path)+strlen(server_addr.sun_path);
    //Call the unlink function to ensure successful creation
    unlink(SERVER_ADDR);
    //Call the bind function to bind
    ret=bind(link_fd,(struct sockaddr*)&server_addr,len);
    //Determine whether the binding is successful
    if(ret==-1)
    {
        sys_err("bind error");
    }

    //Set the maximum number of simultaneous connections to the server
    Listen(link_fd,128);

    cout<<("accept...")<<endl;
    while(1)
    {
        len =sizeof(client_addr);
        cfd=accept(link_fd,(struct sockaddr*)&client_addr,(socklen_t*)&len);
        //Print the file name of the communication
        len-=offsetof(struct sockaddr_un,sun_path);  //To obtain the length of the file name, [subtract the first two bytes of the address structure]
        client_addr.sun_path[len]='\0';
        cout<<"client bind filename "<<client_addr.sun_path<<endl;

        while((size=read(cfd,buf,sizeof(buf)))>0)
        {
            for(int i=0;i<size;i++)
            {
                buf[i]=toupper(buf[i]);
            }
            write(cfd,buf,size);
        }
        close(cfd);
    }
    close(link_fd);
    return 0;
}

Client program

#include<iostream>
#include <stdio.h>
#include <unistd.h>       
#include <sys/socket.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <stddef.h>
#include "wrap.h"
using namespace std;

//Define a port number (server)
#define SERVER_PORT  9527

#define SERVER_ADDR "server.socket"
#define CLIENT_ADDR "client.socket"


int main (int argc,char *argv[])
{
    int  cfd, len;
    struct sockaddr_un servaddr, cliaddr;
    char buf[4096];

    cfd = Socket(AF_UNIX, SOCK_STREAM, 0);

    bzero(&cliaddr, sizeof(cliaddr));
    //Client address structure member initialization, used to create socket file and bind
    cliaddr.sun_family = AF_UNIX;
    strcpy(cliaddr.sun_path,CLIENT_ADDR);
    //Find the header length bytes plus the file length
    len = offsetof(struct sockaddr_un, sun_path) + strlen(cliaddr.sun_path);     /* Calculate the effective length of the client address structure */

    unlink(CLIENT_ADDR);
    bind(cfd, (struct sockaddr *)&cliaddr, len);                                 /* The client also needs bind and cannot rely on automatic binding*/

    
    bzero(&servaddr, sizeof(servaddr));
    //Server address structure member initialization is used to connect / * construct server address*/
    servaddr.sun_family = AF_UNIX;
    strcpy(servaddr.sun_path,SERVER_ADDR);

    len = offsetof(struct sockaddr_un, sun_path) + strlen(servaddr.sun_path);   /* Calculate the effective length of server-side address structure */

    connect(cfd, (struct sockaddr *)&servaddr, len);

    while (fgets(buf, sizeof(buf), stdin) != NULL) {
        write(cfd, buf, strlen(buf));
        len = read(cfd, buf, sizeof(buf));
        write(STDOUT_FILENO, buf, len);
    }

    close(cfd);

    return 0;
}

Operation results

Server:

client:

Keywords: Linux network socket

Added by baennaeck on Sun, 26 Dec 2021 13:09:45 +0200