UNIX域套接字(unix domain)

UNIX域套接字用于在同一台机器上运行的进程之间的通信。

UNIX域套接字提供流和数据报两种接口。

创建一对非命名的、相互连接的UNIX域套接字。

socketpair

1.命名UNIX域套接字

1)套接字地址格式,在linux下如下所示

struct sockaddr_un {

sa_family_t sun_family;

char sun_path[108];

}

绑定该地址:

#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <errno.h>
int main(void)
{
    int fd,size;
    struct sockaddr_un un;
    un.sun_family = AF_UNIX; //unix域
    strcpy(un.sun_path, "foo.socket");
    if ((fd=socket(AF_UNIX, SOCK_STREAM, 0))<0) {
        printf("socket failed\n");
        exit(-1);
    }
    size = sizeof(struct sockaddr_un);
    if (bind(fd, (struct sockaddr *)&un, size) < 0) {
        printf("bind failed:[%s]\n",strerror(errno));
        exit(-1);
    }
    printf("UNIX domain socket bound\n");
    exit(0);
}

# ls -l

srwxr-xr-x   1 dev_old_run swdev     0 Sep  7 13:49 foo.socket

第一位代表文件类型,它是一个socket文件

2.唯一连接

1)serv_listen函数

使用bind、listen和accept

2)serv_accept函数

accept

验证客户进程的身份是该套接字的所有者:验证路径名为一个套接字、权限仅允许用户-读、用户-写以及用户-执行、与套接字相关联的3个时间不比当前时间早30秒。

验证身份这块,我这里理解的是服务器对该路径的判断,只要判断出权限,基本上就可以确定客户端的身份了。

#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <time.h>
#include <stddef.h>

#define QLEN 10
#define STALE 30

int main(void)
{
}

//创建服务端,成功返回fd,错误返回值<0
int serv_listen(const char *name)
{
    int fd,err,rval, len;
    struct sockaddr_un un;

    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
        return -1;
    unlink(name);  //存在文件,先解除连接

    //填充socket地址结构
    memset(&un, 0, sizeof(un));
    un.sun_family = AF_UNIX;
    strcpy(un.sun_path, name);

    //绑定地址到描述符
    if (bind(fd, (struct sockaddr *)&un, len) < 0) {
        rval = -2;
        goto errout;
    }

    if(listen(fd, QLEN) < 0) {
        rval = -3;
        goto errout;
    }
    return(fd);

    errout:
        err = errno;
        close(fd);
        errno = err;
        return(rval);
}

//等待客户连接,并接受它
//同时验证客户的身份
int serv_accept(int listenfd, uid_t *uidptr)
{
    int clifd, rval, err;
    socklen_t len;
    struct sockaddr_un un;
    struct stat statbuf;
    time_t staletime;

    len = sizeof(un);
    if ((clifd = accept(listenfd, (struct sockaddr *)&un, &len)) < 0)
        return -1;

    //确定客户进程的身份是该套接字的所有者
    len -= offsetof(struct sockaddr_un, sun_path); //路径长
    un.sun_path[len]=0; //增加\0结束符

    if (stat(un.sun_path, &statbuf) < 0) {
        rval = -2;
        goto errout;
    }

    // 文件类型检查
    if (S_ISSOCK(statbuf.st_mode)==0) {
        rval = -3;
        goto errout;
    }

    // 文件权限检查
    if((statbuf.st_mode & (S_IRWXG | S_IRWXO)) ||
        statbuf.st_mode & S_IRWXU != S_IRWXU) {
        rval = -4;
        goto errout;
    }

    staletime = time(NULL) - STALE;
    if (statbuf.st_atime < staletime ||
        statbuf.st_ctime < staletime ||
        statbuf.st_mtime < staletime) {
        rval = -5;
        goto errout;
    }

    if (uidptr != NULL)
        *uidptr = statbuf.st_uid; //返回uid
    unlink(un.sun_path);
    return(clifd);

    errout:
        err = errno;
        close(clifd);
        errno = err;
        return rval;
}

3)cli_conn函数

客户端会绑定一个路径名,设置其权限。这样在serv_accept中,服务器可以检验这些权限等来验证客户进程的身份。

接着填充服务器的sockaddr_un结构,调用connect连接到服务器。

#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/un.h>
#include <stddef.h>

#define CLI_PATH "/var/tmp/"
#define CLI_PERM S_IRWXU

int main(void)
{
    exit(0);
}

int cli_conn(const char *name)
{
    int fd, len, err, rval;
    struct sockaddr_un un;

    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
        return -1;

    //填充客户端地址
    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);
    //绑定到套接字
    if (bind(fd, (struct sockaddr *)&un, len) < 0) {
        rval = -2;
        goto errout;
    }

    if (chmod(un.sun_path, CLI_PERM) < 0) {
        rval = -3;
        goto errout;
    }

    //填充服务端地址
    memset(&un, 0, sizeof(un));
    un.sun_family = AF_UNIX;
    strcpy(un.sun_path, name);
    len = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);
    if (connect(fd, (struct sockaddr *)&un, len) < 0) {
        rval = -4;
        goto errout;
    }
    return(fd);

errout:
    err = errno;
    close(fd);
    errno = err;
    return(rval);
}
时间: 2024-10-26 02:07:42

UNIX域套接字(unix domain)的相关文章

Linux高级进程间通信:UNIX域套接字

UNIX域套接字简介 UNIX域套接字用于在同一台机器上运行的进程间的通信.虽然因特网域套接字可用于同一目的,但UNIX域套接字的效率更高.UNIX域套接字仅仅复制数据,它们并不执行协议处理,不需要添加和删除网络报头,无需计算检验和,不要产生顺序号,无需发送确认报文. UNIX域套接字提供流和数据报两种接口.UNIX域数据报服务是可靠的,既不会丢失消息也不会传递错误.UNIX域套接字是套接字和管道之间的混合物.为了创建一对非命名的.相互连接的UNIX域套接字,用户可以使用它们面向网络的域套接字接

《网络编程》Unix 域套接字

概述 Unix 域套接字是一种客户端和服务器在单主机上的 IPC 方法.Unix 域套接字不执行协议处理,不需要添加或删除网络报头,无需验证和,不产生顺序号,无需发送确认报文,比因特网域套接字的效率更高.Unix 域套接字提供字节流(类似于 TCP)和数据报(类似于 UDP)两种接口,UNIX域数据报服务是可靠的,既不会丢失消息也不会传递出错.UNIX域套接字是套接字和管道之间的混合物. Unix 域套接字编程 地址结构: struct sockaddr_un{ sa_family_t sun_

Unix域套接字简介

在Linux系统中,有很多进程间通信方式,套接字(Socket)就是其中的一种.但传统的套接字的用法都是基于TCP/IP协议栈的,需要指定IP地址.如果不同主机上的两个进程进行通信,当然这样做没什么问题.但是,如果只需要在一台机器上的两个不同进程间通信,还要用到IP地址就有点大材小用了. 其实很多人并不一定知道,对于套接字来说,还存在一种叫做Unix域套接字的类别,专门用来解决这个问题.其API的掉用方法基本上和普通TCP/IP的套接字一样,只是有些许差别. 因此,再正式介绍之前,先来复习一下套

使用Unix域套接字进行跨进程通信

Unix域套接字简介 <Unix环境高级编程>中对Unix域套接字有如下介绍: 虽然socketpair函数创建相互连接的一对套接字,但是每一个套接字都没有名字.这意味着无关进程不能使用它们. 我们可以命名unix域套接字,并可将其用于告示服务.但是要注意的是,UNXI与套接字使用的地址不同与因特网域套接字. UNIX域套接字的地址由sockaddr_un结构表示. 在linux2.4.22中,sockaddr_un结构按下列形式定义在有文件 struct sockaddr_un{ sa_fa

unix域套接字的UDP网络编程

unix域套接字的UDP网络编程,服务端如下: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/un.h> #define SA struct sockaddr #define PATHNAME

通过UNIX域套接字传递文件描述符

传送文件描述符是高并发网络服务编程的一种常见实现方式.Nebula 高性能通用网络框架即采用了UNIX域套接字传递文件描述符设计和实现.本文详细说明一下传送文件描述符的应用. 1. TCP服务器程序设计范式 ??开发一个服务器程序,有较多的的程序设计范式可供选择,不同范式有其自身的特点和实用范围,明了不同范式的特性有助于我们服务器程序的开发.常见的TCP服务器程序设计范式有以下几种: 迭代服务器 并发服务器,每个客户请求fork一个子进程 预先派生子进程,每个子进程无保护地调用accept 预先

UNIX域套接字

用户可以在配置文件中指定套接字文件的路径,如--socket=/data/mysql/mysql.sock [[email protected] ~]# mysql -uroot -p123456 -S /data/mysql/mysql.sockWelcome to the MySQL monitor. Commands end with ; or \g.Your MySQL connection id is 3Server version: 5.0.41-log Source distrib

Linux/UNIX套接字连接

套接字连接 套接字是一种通信机子.凭借这样的机制.客户/server系统的开发工作既能够在本地单机上进行.也能够夸网络进行. 套接字的创建和使用与管道是有差别的.由于套接字明白地将客户和server区分开来. 套接字连接: 首先,server应用程序用系统调用socket来创建一个套接字,它是系统分配给该server进程的类似文件描写叙述符的资源,它不能与其它进程共享. 接下来.server进程会给套接字起个名字.本地套接字的名字是Linux文件系统中的文件名称,对于网络套接字它的名字是与客户连

域套接字通信域共享内存通信性能比较

最近碰到一个问题,两个进程间需要实时交换一些数据,数据量不是很大,就72个字节.当时估计简单起见,用的是域套接字的方式. 后续性能测试的时候,忽然发现当网络包并发量很大时,性能忽然大幅下降,用strace跟踪发现,忽然有好多的read,write操作,查看代码跟踪到此处,发现是域套接字需要不断的读写操作,虽然保证了数据的安全按序到达,但是此种操作性能太低.自己就想,两者究竟相差多少呢?跑两个程序比较下,一目了然.代码有些是用的网上现成的,水平有限,勿喷. 结果写在前面防止你看不到:域套接字跟共享