网络编程第十五章:Unix域协议

Unix域提供两种套接字:字节流套接字和数据包套接字.

unix域套接字地址结构:

struct sockaddr_un{
	sa_family_t sun_family;
	char sun_path[104];//必须以空串结尾的路径
};
#include"unp.h"
int main(int argc,char **argv){
	int sockfd;
	socklen_t len;
	struct sockaddr_un addr1,addr2;
	if(argc!=2){
		err_quit("没有路径名");
	}
	sockfd = socket(AF_LOCAL,SOCK_STREAM,0);
	unlink(argv[1]);//删除这个路径名以防它存在
	bzero(&addr1,sizeof(addr1))
	addr1.sa_family_t = AF_LOCAL;
	strncpy(addr1.sun_path,argv[1],sizeof(addr1.sun_path)-1);
	
	bind(sockfd,(SA*)addr1,SUN_LEN(&addr1));
	len = sizeof(addr2);
	getsockname(sockfd,(SA*)addr2,&len);
	printf("bound name = %s,return len = %d \n",addr2.sun_path,len);
	return 0;
}

getsockpair函数
#include
int getsockpair(int family,int type,int protocol,int sockfd[2]);
family参数必须是AF_LOCAL,protocol必须为0,新创建的两个套接字描述符在数组参数里面
套接字函数
1 bind创建的路径名为0777
2 connect调用中指定的路径必须是某个打开的套接字绑定的路径.并且类型必须一致
3 如果Unix套接字调用connect发现这个监听套接字的队列已满,就立即返回一个错误.
4 在一个未绑定的Unix域套接字上发送数据报不会自动给这个套接字捆绑一个路径名.
Unix域字节流客户服务器程序.;
#include"unp.h"
int main(int argc,char **argv){
	int listenfd,connfd;
	socklen_t clilen;
	struct sockaddr_un servaddr,cliaddr;
	void sigchil(int);
	
	listenfd = socket(AF_LOCAL,SOCK_STREAM,0);
	
	unlink(UNIXSTR_PATH);
	bzero(&servaddr,sizeof(servaddr));
	servaddr.sa_family=AF_LOCAL;
	strncp(UNIXSTR_PATH,servaddr.sun_path,sizeof(servaddr.sun_path)-1);
	
	bind(listenfd,(SA*)servaddr,sizeof(servaddr));
	listen(listenfd,LISTENQ)
	sigal(SIGCHLD,sigchil);	
	for(;;){
		clilen =sizeof(cliaddr);
		connfd = accept(listenfd,(SA*)&cliaddr,&clilen);
		if(connnfd<0){
			if(errno == EINTR) continue;
			else err_sys("accept error");
		}
		if((childpid=fork())==0){
			close(listenfd);
			str_echo(connfd);
			exit(0);
		}
		close(connfd);
	}
}




#include"unp.h"
int main(int argc,char **argv){
	int sockfd;
	struct sockaddr_un servaddr;
	sockfd = socket(AF_LOCAL,SOCK_STREAM,0);
	
	unlink(UNIXSTR_PATH);
	bzero(&servaddr,sizeof(sockaddr));
	servadd.sa_family = AF_LOCAL;
	strcpy(servaddr.sun_path,UNIXSTR_PATH);
	
	connect(sockfd,(SA*)&servaddr,sizeof(servaddr));

	str_cli(stdin,sockfd);
	return 0;
}
unix域数据包客户服务器程序
#include"unp.h"
int mian(int argc,char **argv){
	int sockfd;
	struct sockaddr_un servaddr,cliaddr;
	scokfd = socket(AF_LOCAL,SOCK_DGRAM,0);
	
	unlink(UNIXDG_PATH);	
	bzero(&servaddr,sizeof(servaddr));
	servaddr.sun_family = AF_LOCAL;
	strcpy(servaddr.sun_path,UNIXDG_PATH);
	
	bind(sockfd,(SA*)&servaddr,sizeof(servaddr));
	
	dg_echo(sockfd,(SA*)&cliaddr,sizeof(cliaddr));
	
	return 0;
}


#include "unp.h"
int main(int argc,char **argv){
	int sockfd;
	struct sockaddr_un cliaddr,servaddr;
	sockfd = socket(AF_LOCAL,SOCK_DGRAM,0);
	
	unlink(UNIXDG_PATH);
	bzero(&cliaddr,sizeof(cliaddr));
	cliaddr.sun_family = AF_LOCAL;
	strcpy(cliaddr.sun_path,UNIXDG_PATH);
	bind(sockfd,(SA*)&cliaddr,sizeof(cliaddr));
	
	bzero(&servaddr,sizeof(servaddr));
	servaddr.sun_family = AF_LOCAL;
	strcpy(servaddr.sun_path,UNIXDG_PATH);
	
	dg_cli(stdin,sockfd,(SA*)&servaddr,sizeof(servaddr));
	return 0;
}
进程间描述符传递
1 如果是父子进程,那么使用sockpair创建一个可用于父子进程之间交换描述符的流管道
  如果不是父子进程,服务器进程必须创建一个字节流套接字,bind一个路径名在上面,以允许客户connect,客户向服务器发送一个打开某个描述符的请求,服务器吧描述符通过套接字传递给客户
2 发送进程调用Unix函数打开一个描述符
3 发送进程创建一个msghdr结构,其中含有待传递的描述符,作为辅助数据发送,调用sendmsg发送.发送一个描述符会使得这个描述符的引用计数+1;
4 客户调用recvmsg接收这个描述符,

接收发送者的凭证:

可作为辅助数据传递的另一种数据是用户凭证.客户服务器通信时,服务器使用一定手段知道客户身份,以便验证客户是否有权限请求相应服务.

cmsgcred结构传递凭证:

struct cmsgcred{
	pid_t cmcred_pid;//发送进程的PID
	uid_t cmcred_uid;
	uid_t cmcred_euid;
	gid_t cmcred_gid;
	short cmcred_ngroups;
	gid_t cmcred_groups[CMGROUP_MAX];
}

你可能感兴趣的:(网络编程)