zoukankan      html  css  js  c++  java
  • UNIX域套接字(unix domain)

    UNIX域套接字用于在同一台机器上运行的进程之间的通信。
    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
    ");
            exit(-1);
        }
        size = sizeof(struct sockaddr_un);
        if (bind(fd, (struct sockaddr *)&un, size) < 0) {
            printf("bind failed:[%s]
    ",strerror(errno));
            exit(-1);
        }
        printf("UNIX domain socket bound
    ");
        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; //增加结束符
        
        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);
    }
  • 相关阅读:
    【BZOJ1492】【NOI2007】货币兑换(动态规划,CDQ分治,Splay)
    【CF311E】Biologist(网络流,最小割)
    【BZOJ1391】Order(网络流,最小割)
    【BZOJ2007】【NOI2010】海拔(最小割,平面图转对偶图,最短路)
    【BZOJ1001】狼抓兔子(平面图转对偶图,最短路)
    【BZOJ1458】【洛谷4311】士兵占领(网络流)
    【BZOJ2756】奇怪的游戏(二分,网络流)
    【BZOJ1143】祭祀(网络流)
    【BZOJ3504】危桥(网络流)
    【洛谷3852】小朋友(弦图)
  • 原文地址:https://www.cnblogs.com/yanxin880526/p/4787046.html
Copyright © 2011-2022 走看看