第十四章 unix域套接字

unix域套接字实际上不是一个实际的协议,他只是在同一台主机上客户和服务器之间通信时,使用与在不同主机上客户和服务器间通信时相同的API   

unix域套接字分为两种:字节流套接字和数据报套接字

unix域套接字的好处:

1 在同一台主机上进行通信时,是不同主机间通信的两倍

2 unix域套接口可以在同一台主机上,不同进程之间传递套接字描述符

3 unix域套接字可以向服务器提供客户的凭证(用户id或者用户组id)

unix域套接字使用的地址通常是文件系统中一个文件路径(套接口文件:APUE中的4.3节文件类型,是以s开头的),这些文件不是不同的文件,只能作为域套接字通信,不能读写


并且是以s开头的文件

unix域套接字的地址结构是:

struct sockaddr_un
{
	uint8_t sun_len;
	sa_family_sun_family;//AF_LOCAL
	char sun_path[104];//必须是以空结尾的字符串(路径+文件名)
}

int socketpair(int family, int type, intprotocol, int sockfd[2]);

这个函数创建两个互相连接的套接字(socketfd[2])family 是AF_LOCAL, type可以是SOCK_STREAM (字节流)或者SOCK_DGRAM(数据报),协议是0,之后就能够或者两个互相连接的套接字

以SOCK_STREAM调用的socketpair函数得到的套接字叫做流管道(stream pipe),是全双工的,就是这两个套接字是可读可写的

1在unix域套接字进行bind的时候建立套接口文件,其默认的权限值是0777,并被当前的umask修改,看上图就知道,umask是0022 的到的文件权限是0755

2关于bind创建文件中地址参数 sockaddr_un 中的sun_path需要是绝对路径,这样才能不用考虑相对的概念。防止客户端程序也用相对路径,但是和服务器不在同一个目录的考虑

3 connect中的地址中的路径名必须是套接口文件,而且已经被服务端绑定的,以下情况会出错:1 文件路径存在但是不是套接口文件2 路径名存在且是套接口文件,但是没有和该文件绑定的套接口3 就是type必须和服务器相同

4 connect连接unix套接口的时候的权限检查和open函数一样的

5 unix域字节流套接口和TCP一样都给进程提供一个无记录边界的字节流接口

6 unix域套接口connect发现等待队列满了,就直接返回ECONNREFUSRD错误,说连接拒绝错误

7 unix域数据报套接口和UDP一样提供一个保留记录边界的不可靠数据报服务

unix域套接字的客户端:

#include <sys/un.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>

#define MAX_SEND 1025
#define UNIX_PATH "/tmp/sinfor"

void dump_unix(int sock_fd)
{
	char tmp[MAX_SEND] = {0};
	char recv[MAX_SEND] = {0};
	while(fgets(tmp, MAX_SEND, stdin) != NULL)
	{
		write(sock_fd, tmp, strlen(tmp));
		read(sock_fd, recv, MAX_SEND);
		printf("data : %s\n", recv);
		bzero(tmp,MAX_SEND);
		bzero(recv, MAX_SEND);
	}
}
int main(int argc, char** argv)
{
	int conn_sock = socket(AF_LOCAL, SOCK_STREAM, 0);
	if(conn_sock == -1)
	{
		perror("socket fail ");
		return -1;
	}
	struct sockaddr_un addr;
	bzero(&addr, sizeof(addr));
	addr.sun_family = AF_LOCAL;
	strcpy((void*)&addr.sun_path, UNIX_PATH);
	if(connect(conn_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0)
	{
		perror("connect fail ");
		return -1;
	}
	dump_unix(conn_sock);
	close(conn_sock);
	return 0;
}

unix域套接字的服务器;

#include <sys/un.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>

#define MAX_RECV 1025
#define UNIX_SERV_PATH "/tmp/sinfor"
void client_dump(int sock_fd)
{
	char rec[MAX_RECV] = {0};
	int size;
	while((size = read(sock_fd, rec, MAX_RECV)) != 0)
	{
		printf("**********1111************\n");
		printf("recv data is %s\n", rec);
		write(sock_fd, rec, size);
	}
}
void sig_son(int num)
{
	printf("son is %d\n", getpid());
	wait(NULL);
	//return NULL;
}
int main(int argc, char** argv)
{
	int acc_sock, dump_sock;
	acc_sock = socket(AF_LOCAL, SOCK_STREAM, 0);
	if(acc_sock == -1)
	{
		perror("socket func fail ");
		return -1;
	}
	struct sockaddr_un ser_addr, cli_addr;
	ser_addr.sun_family = AF_LOCAL;
	strcpy(ser_addr.sun_path, UNIX_SERV_PATH);
	unlink(UNIX_SERV_PATH);
	bind(acc_sock, (struct sockaddr*)&ser_addr, sizeof(ser_addr));
	listen(acc_sock, 5);
	signal(SIGCHLD, sig_son);
	while(1)
	{
		int len = sizeof(cli_addr);
		dump_sock = accept(acc_sock, (struct sockaddr*)&cli_addr, &len);
		if(dump_sock == -1)
		{
			if(errno == EINTR)
			{
				continue;
			}
			else
			{
				perror("accept fail");
				return -1;
			}
		}
		if(fork() == 0)
		{
			close(acc_sock);
			client_dump(dump_sock);     
			close(dump_sock);
			exit(0);
		}
		close(dump_sock);
	}
	close(acc_sock);
	return 0;
}


这章还有用户认证和描述符通过unix套接字在不同进程之间传递,看完了,太累了,就不写了,有兴趣的自己看看unp吧
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值