概述

Unix 域套接字是一种client和server在单主机上的 IPC 方法。Unix 域套接字不运行协议处理,不须要加入或删除网络报头,无需验证和,不产生顺序号,无需发送确认报文,比因特网域套接字的效率更高。Unix 域套接字提供字节流(类似于 TCP)和数据报(类似于 UDP)两种接口,UNIX域数据报服务是可靠的,既不会丢失消息也不会传递出错。UNIX域套接字是套接字和管道之间的混合物。

Unix 域套接字编程

地址结构:

struct sockaddr_un{
sa_family_t sun_family; /* AF_UNIX */
char sun_path[108]; /* pathname */
};

存放在 sun_path 数组中的路径名必须以空字符结尾。以下是把一个路径名绑定到 Unix 域套接字上实现的程序:

/* 创建一个Unix域套接字,并bind一个路径名 */
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stddef.h> extern void err_sys(const char *, ...);
extern void err_quit(const char *, ...);
int main(int argc, char **argv)
{
int sockfd, size;
socklen_t len;
struct sockaddr_un addr1, addr2; if(argc != 2)
err_quit("usage: %s <pathname>", argv[0]); bzero(&addr1, sizeof(addr1));
addr1.sun_family = AF_UNIX; strncpy(addr1.sun_path, argv[1], sizeof(addr1.sun_path)-1); /* 创建一个Unix域套接字 */
if( (sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
err_sys("socket error"); /* 若路径名在文件系统已存在,则bind会出错;所以先调用unlink删除要绑定的路径名,防止bind出错 */
unlink(argv[1]); /* 将路径名bind绑定到该套接字上 */
size = offsetof(struct sockaddr_un, sun_path) + strlen(addr1.sun_path);
if(bind(sockfd, (struct sockaddr *)&addr1, size) < 0)
err_sys("bind error"); /* 显示已绑定的路径名 */
len = sizeof(addr2);
getsockname(sockfd, (struct sockaddr *)&addr2, &len);
printf("bound name = %s, returned len = %d\n", addr2.sun_path, len); exit(0);
}
$ ./main /tmp/sock
bound name = /tmp/sock, returned len = 12 /*当该路径名存在,且不使用unlink函数时,会出现下面提示*/
$ ./main /tmp/sock
bind error: Address already in use

为了创建一对非命名的,相互连接的 UNXI 域套接字,用户能够使用socketopair函数。事实上现例如以下:

#include <sys/socket.h>
int socketpair(int domain, int type, int protocol, int sockfd[2]);
/* 返回值:若成功则返回0,出错则返回-1 */
/* 说明
* 參数 domain 必须是 AF_LOCAL 或 AF_UNIX,protocol 必须为 0,type 能够是 SOCK_STREAM 或 SOCK_DGRAM,新创建的两个套接字描写叙述符作为sockfd[0]和sockfd[1]返回;

Unix 域套接字函数

与因特网域套接字相比,Unix 域套接字有下面的差别:

  1. 由 bind 创建的路径名默认訪问权限应为 0777,并按当前 umask 值进行改动;
  2. 路径名必须是一个绝对路径名,避免使用相对路径名。由于它的解析依赖于调用者的当前工作文件夹,若server绑定的是一个相对路径名,则client和server必须在同样的文件夹才干正常工作;
  3. 在 connect 调用中指定的路径名必须是一个当前绑定在某个已打开的 Unix 域套接字上的路径名,并且套接字类型必须一致;
  4. 调用 connect 连接一个 Unix 域套接字涉及的权限測试等价于调用 open 以仅仅写方式訪问对应的路径名;
  5. Unix 域字节流套接字类似于 TCP 套接字:它们都为进程提供一个无记录边界的字节流接口;
  6. 在 Unix 域字节流套接字中,若 connect 调用时发现监听套接字的队列已满,则马上返回 ECONNREFUSED 错误。而 TCP 套接字遇到这样的情况,TCP 监听套接字忽略这些到达的 SYN 连接请求,TCP client则会重发数次 SYN 报文段;
  7. Unix 域数据报套接字类似于 UDP 套接字:它们都提供一个保留记录边界的不可靠数据报;
  8. 为一个未绑定路径名的 Unix 套接字发送数据时,不会自己主动给该套接字绑定一个路径名。而 UDP 套接字在给一个未绑定的 UDP 套接字发送数据时,会自己主动为其绑定一个暂时port;

Unix 域字节流编程

server程序:

#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stddef.h>
#include <signal.h>
#include <errno.h> #define QLEN 1024
typedef void Sigfunc(int); extern void err_sys(const char *, ...);
extern void err_quit(const char *, ...);
extern void str_echo(int);
static Sigfunc *MySignal(int signo, Sigfunc *func);
static Sigfunc *M_signal(int signo, Sigfunc *func);
static void sig_chld(int); int main(int argc, char **argv)
{
int sockfd, conndfd, size;
socklen_t len;
pid_t childpid;
struct sockaddr_un cliaddr, servaddr; if(argc != 2)
err_quit("usage: %s <pathname>", argv[0]); bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_UNIX; strcpy(servaddr.sun_path, argv[1]); /* 创建一个Unix域套接字 */
if( (sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
err_sys("socket error"); /* 若路径名在文件系统已存在,则bind会出错;所以先调用unlink删除要绑定的路径名,防止bind出错 */
unlink(argv[1]); /* 将路径名bind绑定到该套接字上 */
size = offsetof(struct sockaddr_un, sun_path) + strlen(servaddr.sun_path);
if(bind(sockfd, (struct sockaddr *)&servaddr, size) < 0)
err_sys("bind error"); /* 监听套接字 */
if(listen(sockfd, QLEN) < 0)
{
close(sockfd);
err_sys("listen error");
} /* 信号处理 */
MySignal(SIGCHLD, sig_chld); for( ; ;)
{
len = sizeof(cliaddr);
if( (conndfd = accept(sockfd, (struct sockaddr *)&cliaddr, &len)) < 0)
{
if(errno == EINTR)
continue;
else
err_sys("accept error");
}
} if( (childpid = fork()) == 0)
{
close(sockfd);
str_echo(conndfd);
exit(0);
}
close(conndfd);
} void sig_chld(int signo)
{
pid_t pid;
int stat;
while( (pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d terminated\n", pid);
return;
}
static Sigfunc *MySignal(int signo, Sigfunc *func)
{
Sigfunc *sigfunc;
if( (sigfunc = M_signal(signo, func)) == SIG_ERR)
err_sys("signal error");
return (sigfunc);
} static Sigfunc *M_signal(int signo, Sigfunc *func)
{
struct sigaction act, oact; /* 设置信号处理函数 */
act.sa_handler = func;
/* 初始化信号集 */
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if(signo == SIGALRM)
{/* 若是SIGALRM信号,则系统不会自己主动重新启动 */
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT;
#endif
}
else
{/* 其余信号设置为系统会自己主动重新启动 */
#ifdef SA_RESTART
act.sa_flags |= SA_RESTART;
#endif
}
/* 调用 sigaction 函数 */
if(sigaction(signo, &act, &oact) < 0)
return(SIG_ERR);
return(oact.sa_handler);
}

client程序:

#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h> extern void err_sys(const char *, ...);
extern void err_quit(const char *, ...);
extern void str_cli(FILE *, int); int
main(int argc, char **argv)
{
int sockfd;
struct sockaddr_un servaddr; if(argc != 2)
err_quit("usage: %s <pathname>", argv[0]);
if( (sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
err_sys("socket error"); bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_UNIX;
strcpy(servaddr.sun_path, argv[1]); int err;
err = connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
if( err < 0)
err_sys("connect error"); str_cli(stdin, sockfd); /* do it all */ exit(0);
}

參考资料:

《Unix 网络编程》

《网络编程》Unix 域套接字的更多相关文章

  1. UNIX网络编程——UNIX域套接字编程和socketpair 函数

    一.UNIX Domain Socket IPC socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket.虽然网络soc ...

  2. unix域套接字UDP网络编程

    unix域套接字UDP网络编程,服务器如下面: #include <stdio.h> #include <stdlib.h> #include <string.h> ...

  3. UNIX网络编程——通过UNIX域套接字传递描述符和 sendmsg/recvmsg 函数

    在前面我们介绍了UNIX域套接字编程,更重要的一点是UNIX域套接字可以在同一台主机上各进程之间传递文件描述符. 下面先来看两个函数: #include <sys/types.h> #in ...

  4. UNIX域套接字编程和socketpair 函数

    一.UNIX Domain Socket IPC socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket.虽然网络soc ...

  5. UNIX网络编程——原始套接字(dos攻击)

    原始套接字(SOCK_RAW).应用原始套接字,我们可以编写出由TCP和UDP套接字不能够实现的功能. 注意原始套接字只能够由有 root权限的人创建. 可以参考前面的博客<<UNIX网络 ...

  6. UNIX网络编程——原始套接字的魔力【续】

    如何从链路层直接发送数据帧 上一篇里面提到的是从链路层"收发"数据,该篇是从链路层发送数据帧. 上一节我们主要研究了如何从链路层直接接收数据帧,可以通过bind函数来将原始套接字绑 ...

  7. 高级进程间通信之UNIX域套接字

    UNIX域套接字用于在同一台机器上运行的进程之间的通信.虽然因特网域套接字可用于同一目的,但UNIX域套接字的效率更高.UNIX域套接字仅仅复制数据:它们并不执行协议处理,不需要添加或删除网络报头,无 ...

  8. 通过UNIX域套接字传递描述符的应用

      传送文件描述符是高并发网络服务编程的一种常见实现方式.Nebula 高性能通用网络框架即采用了UNIX域套接字传递文件描述符设计和实现.本文详细说明一下传送文件描述符的应用. 1. TCP服务器程 ...

  9. unix进程间通信方式(下)-unix域套接字(转)

    在之前的博客中已经总结了其它7种进程间的通信方式.unix域套接字用于在同一台计算机上的进程间通信,虽然因特网域套接字可用于同一目的,但是unix域套接字的效率更高.unix域套接字并不进行协议处理, ...

随机推荐

  1. the C programming language 阅读笔记1

    读了一遍著名的<the C programming language>,果然如听说的一样,讲解基础透彻,案例简单典型,确实自己C语言还有很多细节点不是很清楚. 总结一下阅读的收获(部分原书 ...

  2. Oracle inner join、left join、right join 、+左边或者右边的区别

    我们以Oracle自带的表来做例子 主要两张表:dept.emp 一个是部门,一个是员工表结构如下: emp name null? Type Empno not null number(4) enam ...

  3. WIX 学习笔记- 1 简介

    一个项目 Code Complete 后,程序员们欢欣鼓舞,以为事情到此结束,可以 Happy 了.其实 Code Complete 五十之于百里.一个没有运行在设备上,为人们创造价值的项目是注定失败 ...

  4. 排序-java

    今天座右铭----每天的学习会让我们不断地进步! 往往面试中都会让我们用一种排序方法做一道排序题,下面我就罗列出快速排序.冒泡排序.插入排序.选择排序的java代码! 1.快速排序 public cl ...

  5. powerdesigner for sqlserver的一些实用配置

    在实用powerdesigner生成sqlserver 数据表时常常遇到一些问题: 1.数据中定义的字段名称相同生成物理模型时会报错. 2.数据各表之间的主键不能定义一样的名称. 我现在的需求是将数据 ...

  6. 解析微信node开发;拿token

    获取token,本着两个原则, 1.先查询是否有token,有的话判断其时间是否与上一次请求时间差是否超过7100: a.不超过,直接用得到: b.超过,再获取刷新: 2.没有token获取刷新tok ...

  7. swift论坛正式上线

    www.iswifting.com swift论坛正式上线.有问答专区,也有技术分享区,还有学习资料区,大家一起学习成长! 2014中国互联网大会于8月26日开幕. 政府主管部门.行业专家.企业领袖将 ...

  8. MongoDB 启动异常

    今天启动MongoDB遇到异常状况 mongodb warning: 32-bit servers don't have journaling enable 解决方法: 删除数据库目录的.lock文件 ...

  9. ZOJ 1563 Pearls(动态规划)

    /* 分析: 因为他给的数据是递增的 而求得是这些数据总的 最优解 所以我们可以考虑,它的子问题求解不影响总的求解 也就是我们可以先求出 第一个的最优解 第二个....以此类推到总的最优解 那么我们想 ...

  10. sql server 2000 对应 sql server 2005的row_number()、rank()、DENSE_RANK( )、ntile( )等用法

    转自CSDN:http://blog.csdn.net/htl258/article/details/4006717 SQL server 2005新增的几个函数,分别是row_number( ).r ...