- 命名套接字之间互相通信。可以利用网络套接字的接口进行绑定、监听、接收数据等等
一、域套接字地址
#include <sys/un.h>
struct sockaddr_un{
sa_family_t sun_family; /*AF_UNIX*/
char sun_path[108]; /*pathname*/
}
- 因为域套接字是在同一台计算机上的不同进程之间通信。
- 系统提供了结构体,当域套接字与此结构体绑定之后。进行之间就可以通过域套接字进行互相访问
sun_family:
- 域套接字进行通信的协议
sun_path:
- 用于包含一个路径名
S_IFSOCK类型文件
- 当我们将一个地址绑定到一个域套接字上之后,系统会用该路径名创建一个S_IFSOCK类型的文件
- 该文件仅用于向客户进程告示套接字名字。文件无法打开,也不能由应用程序用于通信
注意事项:
- 当我们绑定同一地址时,如果该文件已经存在,那么bind就会失败。当关闭套接字时,并不自动删除该文件,所以要确保在应用程序退出前,对该文件执行解除链接操作
二、命名域套接字的创建(socket)
- 通过socket函数进行创建
int fd=socket(AF_UNIX,SOCK_STREAM,0);
三、命名套接字的绑定(bind)
- 绑定时,要注意绑定的地址的文件不是系统中已存在的文件
下面演示创建一个域套接字并且为域套接字绑定一个地址:
- 下面程序中先调用offsetof宏计算sum_path成员在socjaddr_un结构体中的偏移量,然后将结果与路径名长度相加。将得到的结果作为地址的总长度,为什么这样设计???因为sockaddr_un结构体在不同的系统之间实现不同,所以这样增加可移植性
- offsetof宏见文章:https://blog.csdn.net/qq_41453285/article/details/90742619
#include <stddef.h>
int main()
{
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){
perror("socket")
exit(EXIT_FAILURE);
}
size=offsetof(struct sockaddr_un,sun_path)+strlen(un.sun_path);
if(bind(fd,(struct sockaddr*)&un,size)){
perror("bind")
exit(EXIT_FAILURE);
}
printf("UNIX domain socket bound\n");
exit(0);
}
四、域套接字的监听、接受、连接(listen、accept、connect)
- 域套接字可以调用网络套接字来实现不同进程之间的通信。类似于与TCP、UDP之间的通信
- 下面使我们自定义的3个函数:
serv_listen函数:
- 参数name:服务端调用serv_listen函数声明它要在一个众所周知的名字上监听客户进程的连接请求。客户端通过这个名字来连接到服务器
- 返回值:返回值是客户端用于连接请求的服务器域套接字
- 此函数中包含了服务端的socket、bind、listen三个步骤的函数
#define QLEN 10 int serv_listen(const char *name) { int fd, len, err, rval; struct sockaddr_un un; if (strlen(name) >= sizeof(un.sun_path)) { errno = ENAMETOOLONG; return(-1); } if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) return(-2); unlink(name); 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 (bind(fd, (struct sockaddr *)&un, len) < 0) { rval = -3; goto errout; } if (listen(fd, QLEN) < 0) { rval = -4; goto errout; } return(fd); errout: err = errno; close(fd); errno = err; return(rval); }
serv_accept函数:
- 此函数用来接受客户端的请求,模仿accept函数
- listenfd:服务端的域套接字
- uidptr:当有一个客户进程连接之后,此参数存放客户进程的有效用户ID
#define STALE 30 /* client's name can't be older than this (sec) */ int serv_accept(int listenfd, uid_t *uidptr) { int clifd, err, rval; socklen_t len; time_t staletime; struct sockaddr_un un; struct stat statbuf; char *name; if ((name = malloc(sizeof(un.sun_path + 1))) == NULL) return(-1); len = sizeof(un); if ((clifd = accept(listenfd, (struct sockaddr *)&un, &len)) < 0) { free(name); return(-2); /* often errno=EINTR, if signal caught */ } len -= offsetof(struct sockaddr_un, sun_path); /* len of pathname */ memcpy(name, un.sun_path, len); name[len] = 0; /* null terminate */ if (stat(name, &statbuf) < 0) { rval = -3; goto errout; } #ifdef S_ISSOCK /* not defined for SVR4 */ if (S_ISSOCK(statbuf.st_mode) == 0) { rval = -4; /* not a socket */ goto errout; } #endif if ((statbuf.st_mode & (S_IRWXG | S_IRWXO)) || (statbuf.st_mode & S_IRWXU) != S_IRWXU) { rval = -5; /* is not rwx------ */ goto errout; } staletime = time(NULL) - STALE; if (statbuf.st_atime < staletime || statbuf.st_ctime < staletime || statbuf.st_mtime < staletime) { rval = -6; /* i-node is too old */ goto errout; } if (uidptr != NULL) *uidptr = statbuf.st_uid; /* return uid of caller */ unlink(name); free(name); return(clifd); errout: err = errno; close(clifd); free(name); errno = err; return(rval); }
cli_conn函数:
#define CLI_PATH "/var/tmp/" #define CLI_PERM S_IRWXU /* rwx for user only */ int cli_conn(const char *name) { int fd, len, err, rval; struct sockaddr_un un, sun; int do_unlink = 0; if (strlen(name) >= sizeof(un.sun_path)) { errno = ENAMETOOLONG; return(-1); } 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%05ld", CLI_PATH, (long)getpid()); printf("file is %s\n", un.sun_path); 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; do_unlink = 1; goto errout; } memset(&sun, 0, sizeof(sun)); sun.sun_family = AF_UNIX; strcpy(sun.sun_path, name); len = offsetof(struct sockaddr_un, sun_path) + strlen(name); if (connect(fd, (struct sockaddr *)&sun, len) < 0) { rval = -4; do_unlink = 1; goto errout; } return(fd); errout: err = errno; close(fd); if (do_unlink) unlink(un.sun_path); errno = err; return(rval); }