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;
}
#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域套接字上发送数据报不会自动给这个套接字捆绑一个路径名.
#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;
}
#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];
}