UNIX(网络编程-域套接字):04---命名套接字通信(struct sockaddr_un)

  • 命名套接字之间互相通信。可以利用网络套接字的接口进行绑定、监听、接收数据等等

一、域套接字地址

#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);
}

UNIX(网络编程-域套接字):04---命名套接字通信(struct sockaddr_un)

四、域套接字的监听、接受、连接(listen、accept、connect)

  • 域套接字可以调用网络套接字来实现不同进程之间的通信。类似于与TCP、UDP之间的通信
  • 下面使我们自定义的3个函数:

UNIX(网络编程-域套接字):04---命名套接字通信(struct sockaddr_un)

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);
}

 

上一篇:51Nod 1344 走格子(贪心


下一篇:VM克隆centos7虚拟机并配置网络