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