UNIX域协议并不是一个实际的协议族,而是在单个主机上执行客户/服务器通信的一种方法,所用API与在不同主机上执行客户/服务器通信所使用的API相同。UNIX域协议可以视为IPC方法之一,Unix域协议主要用在同一台机子(仅能用于本地进程间的通信)的不同进程之间传递套接字。为什么不用TCP或者UDP套接字呢?
1)在同一台主机上, UNIX域套接字更有效率, 几乎是TCP的两倍(由于UNIX域套接字不需要经过网络协议栈,不需要打包/拆包,计算校验和,维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程, 而且UNIX域协议机制本质上就是可靠的通讯, 而网络协议是为不可靠的通讯设计的)。
2)UNIX域套接字可以在同一台主机上各进程之间传递文件描述符。
3)UNIX域套接字较新的实现把客户的凭证(用户ID和组ID)提供给服务器,从而能够提供额外的安全检查措施。
注意:UNIX域套接字也提供面向流和面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIX套接字也是可靠的,消息既不会丢失也不会顺序错乱。Unix域协议表示协议地址的是路径名,而不是Internet域的IP地址和端口号。
UNIX域套接字地址结构:
#define UNIX_PATH_MAX 108
struct sockaddr_un
{
sa_family_t sun_family; /* AF_UNIX */
char sun_path[UNIX_PATH_MAX]; /* pathname */
};
至于通信程序的话,和使用TCP的通信并没有很大的区别,下面给出基于UNIX域套接字的server/client程序源码
:
/**Server端**/
int main()
{
int listenfd = socket(AF_UNIX, SOCK_STREAM, 0); //使用AF_UNIX 或者AF_LOCAL
if (listenfd == -1)
err_exit("socket error");
char pathname[] = "/tmp/test_for_unix";
unlink(pathname);//如果文件系统中已存在该路径名,bind将会失败。为此我们先调用unlink删除这个路径名,以防止它已经存在
struct sockaddr_un servAddr;
servAddr.sun_family = AF_UNIX;
strcpy(servAddr.sun_path, pathname);
if (bind(listenfd, (struct sockaddr *)&servAddr, sizeof(servAddr)) == -1)
err_exit("bind error");
if (listen(listenfd, SOMAXCONN) == -1)
err_exit("listen error");
while (1)
{
int connfd = accept(listenfd, NULL, NULL);
if (connfd == -1)
{
if(connfd==EINTR)
continue;
err_exit("accept");
}
}
return 0;
}