0x01 Unix domain socket 的作用
1,允许在同一host上的不同进程通信,另外一种IPC方式
2,可以方便的实现子进程向父进程传递文件描述符
3,通过 socketpair 可以在父子进程之间通过文件描述模拟管道,更加高效
0x02 创建 Unix domain docket
1,地址结构
struct sockaddr_un {
sa_family_t sun_family; //固定为 AF_UNIX
char sun_path[108]; //Unix domain socket中socket地址是一个文件路径名
};
说明:
1,对于路径名,各系统之间的限制长度不同,但是为了移植行,一般推荐使用一个较短的路径名。
2,最好是通过 snprintf 或者 strcopy 函数来避免缓冲区溢出的问题
2,创建一个 Unix socket 同时将 socket 地址绑定到指定路径上
char* socketName = "/tmp/mysock.sock";
int sfd;
struct sockaddr_un addr;
sfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sfd == -1) {
errExit("socket");
}
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socketName, sizeof(addr.sun_path) - 1);
if (bind(sfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) == -1) {
errExit("bind");
}
说明:
1,使用memset函数来初始化结构体,这是通用的做法了
2,通过strncopy来将 sun_path 初始化成其长度减1的目的是要保证其值一定是以null结尾的
3,一个使用 Unix domain socket 互相通信的客户端-服务器程序
4,使用 Unix domain socket 在父子进程之间传递文件描述符
有一种场景,一个进程创建一对socket,然后把它们相互连起来。
这可以通过使用 socket, bind, listen, connect 这些函数相互组合实现,但是另外一个系统调用函数 socketpair 提供了一种
快捷方式。
由于这个函数的存在,这就使得在父子进程之间传递文件描述符变得异常简单了,因为当执行 fork 之后子进程可以继承父进程的文件描述符
所以我们可以在父进程中调用 socketpair 然后再执行 fork,这样父子进程就可以通过文件描述符进行通信了。
示例代码:
int UnixDomainSocketDemo()
{
int sockfd[2];
if ( socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) == -1 ) {
perror("socketpair");
exit(0);
}
int pid = fork();
if ( pid == -1 ) {
perror("fork");
exit(0);
}
if ( pid == 0 ) { //child
close(sockfd[0]);
char buf[] = "koma";
write(sockfd[1], buf, sizeof(buf));
} else {
close(sockfd[1]);
sleep(3);
char buf[1024];
read(sockfd[0], buf, 1024);
printf("recv data: %s\n", buf);
int status;
waitpid(pid, &status, WNOHANG);
}
}
int main(int argc, char * argv[]) {
UnixDomainSocketDemo();
return 0;
}