網絡編程第十五章: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<sys/socket.h>
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];
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章