一.Unix域套接字的产生原因及特性
1.产生原因:
在之前的学习中我们学习了网络套接字,实现了不同主机间的进程通讯,同时为了保证数据传输的可靠性,网络套接字中增加了许多校验,应答,序列号等机制,但是假如我们想要实现本机两个进程间通讯的话,使用同样的方法行不行??当然行,但是大材小用了,本来本地进程间通讯就比较可靠,不用这么麻烦,为了提高效率,出现了Unix域套接字。
2.特性
- UNIX域套接字用于在同一台计算机上运行的进程之间的通信。
- UNIX域套接字提供流和数据报两种接口。UNIX域数据报服务是可靠的,既不会丢失消息也不会传递出错。UNIX域套接 字是套接字和管道之间的混合物。
- UNIX域套接字域传统套接字的区别是用路径名表示协议族的描述
- UNIX域套接字可以在同一台主机上各进程之间传递文件描述符
3.进程间通讯机制比较
我们知道了它是是一种进程间通讯的方式,常用于前后台进程通信,但是我们在之前的学习中知道进程间的通讯机制还有有管道,共享内存,信号量,信号,消息队列等。
回顾一下进程间通讯机制:
1》进程间数据共享
- 管道,消息队列,共享内存,unix 域套接字
- 易用性:消息队列 > unix 域套接字 > 管道 > 共享内存(配合信号量使用)
- 效率:共享内存 > unix 域套接字 > 管道 > 消息队列
- 常用:共享内存,unix 域套接字
2》异步通讯
- 信号
3》 同步和互斥
- 信号量
从上面比较也可以看出和其他进程间通信方式相比使用方便、效率更高
4.unix 域套接字编程
unix 域套接字分为流式套接字和用户数据报套接字
看着和我们之前的socket编程基本上没有什么区别,但是注意的是之前我们填充的是网络地址(IP和端口),现在要用本地地址,我们需要填充的结构体是sockaddr_un.
文件名要事先不存在,路径一般给绝对路径。
实现原理
借助文件来实现进程间通讯。
看个实例我们就知道怎么写了:
server.c
#define UNIX_DOMAIN_FILE "/tmp/my_domain_file.1"
/* 1. 创建socket fd */
if ((fd = socket (AF_LOCAL, SOCK_STREAM, 0)) < 0) { //基于本地的TCP通信
perror ("socket");
exit (1);
}
/* 允许绑定地址快速重用 */
int b_reuse = 1;
setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof (int));
/* 2.1 填充sockaddr_un结构体变量 */
struct sockaddr_un sun;
bzero(&sun, sizeof(sun));
sun.sun_family = AF_LOCAL;
/* 如果UNIX_DOMAIN_FILE所指向的文件存在,则删除 */
if(!access(UNIX_DOMAIN_FILE, F_OK)) {
unlink(UNIX_DOMAIN_FILE);
}
strncpy(sun.sun_path, UNIX_DOMAIN_FILE, strlen( UNIX_DOMAIN_FILE));
/*2.2 绑定 */
if (bind (fd, (struct sockaddr *) &sun, sizeof (sun)) < 0) {
perror ("bind");
exit (1);
}
/*3. 调用listen()把主动套接字变成被动套接字 */
if (listen (fd, BACKLOG) < 0) {
perror ("listen");
exit (1);
}
printf ("Unix domain server starting....OK!\n");
int newfd = -1;
/*4. 阻塞等待客户端连接请求 */
while(1) {
if ((newfd = accept (fd, NULL,NULL)) < 0) {
perror ("accept");
break;
}
}
client.c
/* 1. 创建socket fd */
if ((fd = socket (AF_LOCAL, SOCK_STREAM, 0)) < 0) {
perror ("socket");
exit (1);
}
/*2.连接服务器 */
/*2.1 填充struct sockaddr_un结构体变量 */
bzero (&sun, sizeof (sun));
sun.sun_family = AF_LOCAL;
/*确保UNIX_DOMAIN_FILE要先存在并且可写,不存在则退出 */
if( access(UNIX_DOMAIN_FILE, F_OK| W_OK) < 0){
exit(1);
}
strncpy(sun.sun_path, UNIX_DOMAIN_FILE, strlen( UNIX_DOMAIN_FILE));
if (connect (fd, (struct sockaddr *) &sun, sizeof (sun)) < 0) {
perror ("connect");
exit (1);
}
printf ("Unix domain Client staring...OK!\n");
大概的使用方法就是这样的,在什么时候用什么进程通讯,灵活的选用和程序的一些防护,需要慢慢的去学习。