域套接字简介及范例(三)————抽象路径名

什么叫抽象路径名,这其实是Linux特有的一个特性,它允许将一个Unix域套接字绑定到一个名字上,且不会在文件系统中创建这个名字的文件。如果要创建一个抽象名字空间的绑定,必须要将sun_path字段的第一个字节设置成NULL('\0'),而且和普通的文件系统名字空间不同的是,系统会用sun_path除第一个字节之后余下的所有字节当做抽象名字。也就是说在解析抽象路径名时需要用到sun_path字段当中所有的字节,而不是像解析普通路径名一样,解析到第一个NULL就可以停止了。因为不会再在文件系统中创建文件了,所以对于抽象路径名来说,就不需要担心与文件系统中已存在的文件产生名字冲突的问题了,也不需要在使用完套接字之后删除附带产生的这个文件了,当套接字被关闭之后会自动删除这个抽象名。

抽象路径名还可以解决路径权限的问题。如果在软件中使用绝对路径,为了方便,最好就是使用系统目录下的文件,这样的话执行程序就只能使用root权限。如果使用相对路径或者用户目录下的路径,那又会存在软件更改运行环境之后可能无法运行的问题。采用抽象路径就不会有这种问题。

本例采用类似UDP的数据包形式:

服务端:

#include "../common.h"
#define FILE_PATH_SER "my_socket_s"
#define FILE_PATH_CLI "my_socket_c"

int main()
{
	int serFd,cliFd;
	struct sockaddr_un s_addr,c_addr;
	char recvbuf[1024] = {0};
	char sendbuf[1024] = {0};
    int ret = -1;
	int addrLen = sizeof(s_addr);

	if((serFd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
    {
		printf("socket serFd fail\n");
		return 0;
	}

    if((cliFd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
    {
		printf("socket cliFd fail\n");
		return 0;
	}
    //unlink(FILE_PATH_SER); //删除文件,保证文件不存在
	memset(&s_addr, 0, sizeof(struct sockaddr_un));
	s_addr.sun_family  = AF_UNIX;
	//strcpy(s_addr.sun_path,FILE_PATH_SER);
	s_addr.sun_path[0] = '\0';
	memcpy(s_addr.sun_path+1,FILE_PATH_SER,sizeof(FILE_PATH_SER));

    c_addr.sun_family  = AF_UNIX;
	//strcpy(c_addr.sun_path,FILE_PATH_CLI);
    c_addr.sun_path[0] = '\0';
	memcpy(c_addr.sun_path+1,FILE_PATH_CLI,sizeof(FILE_PATH_CLI));

	//必须绑定
	if(bind(serFd, (struct sockaddr *)&s_addr, sizeof(struct sockaddr)) == -1)
    {
		printf("bind fail\n");
		return 0;
	}
	while(1)
	{
		ret = recvfrom(serFd, recvbuf, 1024, 0,(struct sockaddr *)&s_addr, (socklen_t*)&addrLen);
        if(ret < 0)
        {
            char *errorMsg = strerror(errno);
			printf("recv from cli fail:%s\n", errorMsg);
			break;
        }
		printf("recv '%s' from cli ...\n",recvbuf);
        sprintf(sendbuf,"ser recv '%s'",recvbuf);
        ret = sendto(cliFd,sendbuf, 1024, 0,(struct sockaddr *)&c_addr, sizeof(struct sockaddr));
        if(ret < 0)
        {
            char *errorMsg = strerror(errno);
			printf("send to cli fail:%s\n", errorMsg);
			break;
        }
        else
        {
            printf("send '%s' to cli success ...\n\n",sendbuf);
        }
    }

    close(serFd);
    close(cliFd);
}

 

客户端:

#include "../common.h"
#define FILE_PATH_SER "my_socket_s"
#define FILE_PATH_CLI "my_socket_c"
/*
按照普通的包套接字创建和连接的流程,只是在服务器端调用bind()函数绑定了一个地址,而客户端并没有地址。
这在流式套接字中没有问题,内核已经在服务器端调用accept()函数接收一个客户端连接时创建了一个新的套接字,
从而将一一对应关系绑定到了这个新的套接字上了。所以,对于包套接字来说,
在客户端还需要再调用bind()函数绑定一次,人为的创建一个客户端地址,且这个客户端路径名地址显然不能和服务器端的路径名相同。
这样看来,并没有实际的客户端与服务器之分.
*/
int main()
{
	int serFd,cliFd;
	struct sockaddr_un s_addr,c_addr;
	int ret = -1;
	char sendbuf[1024];
	char recvbuf[1024];
	int addrLen = sizeof(s_addr);
 
	if((serFd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
    {
		printf("socket serFd fail\n");
		return 0;
	}
    if((cliFd = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
    {
		printf("socket cliFd fail\n");
		return 0;
	}
	memset(&s_addr, 0, sizeof(struct sockaddr_un));
    memset(&c_addr, 0, sizeof(struct sockaddr_un));
    
	s_addr.sun_family  = AF_UNIX;
	//strcpy(s_addr.sun_path,FILE_PATH_SER);
	s_addr.sun_path[0] = '\0';
	memcpy(s_addr.sun_path+1,FILE_PATH_SER,sizeof(FILE_PATH_SER));

    c_addr.sun_family = AF_UNIX;
    //strcpy(c_addr.sun_path,FILE_PATH_CLI);
	c_addr.sun_path[0] = '\0';
	memcpy(c_addr.sun_path+1,FILE_PATH_CLI,sizeof(FILE_PATH_CLI));
	
    //unlink(FILE_PATH_CLI);
    if(bind(cliFd, (struct sockaddr *)&c_addr, sizeof(struct sockaddr)) == -1)
    {
		printf("bind fail\n");
		return 0;
	}

	while(1)
	{
		printf("please input send message:");
		scanf("%s",sendbuf);
        getchar();
		if((ret = sendto(serFd, sendbuf, 1024, 0,(struct sockaddr *)&s_addr, sizeof(struct sockaddr))) < 0)
		{
            char *errorMsg = strerror(errno);
			printf("send to ser fail:%s\n", errorMsg);
			break;
		}
		printf("send '%s' to ser success ...\n",sendbuf);
        
        ret = recvfrom(cliFd, recvbuf, 1024, 0,(struct sockaddr *)&c_addr, (socklen_t*)&addrLen);
        if(ret < 0)
        {
            char *errorMsg = strerror(errno);
			printf("recv from ser fail:%s\n", errorMsg);
			break;
        }
        else
        {
            printf("recv (%s) from ser ...\n\n",recvbuf);
        }
        
	}

    close(serFd);
    close(cliFd);
}

这样的话,即使服务端和客户端不在同一个目录下,使用相对路径也是可以相互通信的,这在域套接字简介及范例(二)————数据包形式中是无法实现的。同样的,我们在其他任何位置运行相同的程序,都无法再次使用bind进行绑定,可见抽象路径名本身对于内核而言是全局同步的。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值