UNIX网络编程——UNIX域套接字编程和socketpair 函数
一、UNIX Domain Socket IPC
socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket。虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是UNIX Domain Socket用于IPC更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。UNIX域套接字与TCP套接字相比较,在同一台主机的传输速度前者是后者的两倍。这是因为,IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。UNIX Domain Socket也提供面向流和面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIXDomain Socket也是可靠的,消息既不会丢失也不会顺序错乱。
使用UNIX Domain Socket的过程和网络socket十分相似,也要先调用socket()创建一个socket文件描述符,address family指定为AF_UNIX,type可以选择SOCK_DGRAM或SOCK_STREAM,protocol参数仍然指定为0即可。
UNIX Domain Socket与网络socket编程最明显的不同在于地址格式不同,用结构体sockaddr_un表示,网络编程的socket地址是IP地址加端口号,而UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径,这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,则bind()错误返回。
#define UNIX_PATH_MAX 108
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[UNIX_PATH_MAX]; /* pathname */
};
二、回射/客户服务器程序
通信的流程跟前面说过的tcp/udp 是类似的。下面直接来看服务器serv.c程序:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include<sys/un.h> #define ERR_EXIT(m) \
do { \
perror(m); \
exit(EXIT_FAILURE); \
} while (0) void echo_ser(int conn)
{
char recvbuf[1024];
int n;
while (1)
{ memset(recvbuf, 0, sizeof(recvbuf));
n = read(conn, recvbuf, sizeof(recvbuf));
if (n == -1)
{
if (n == EINTR)
continue; ERR_EXIT("read error");
} else if (n == 0)
{
printf("client close\n");
break;
} fputs(recvbuf, stdout);
write(conn, recvbuf, strlen(recvbuf));
} close(conn);
} /* unix domain socket与TCP套接字相比较,在同一台主机的传输速度前者是后者的两倍。*/
int main(void)
{
int listenfd;
if ((listenfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
ERR_EXIT("socket error"); unlink("/tmp/test socket"); //地址复用
struct sockaddr_un servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sun_family = AF_UNIX;
strcpy(servaddr.sun_path, "/tmp/test socket"); if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
ERR_EXIT("bind error"); if (listen(listenfd, SOMAXCONN) < 0)
ERR_EXIT("listen error"); int conn;
pid_t pid; while (1)
{ conn = accept(listenfd, NULL, NULL);
if (conn == -1)
{ if (conn == EINTR)
continue;
ERR_EXIT("accept error");
} pid = fork();
if (pid == -1)
ERR_EXIT("fork error");
if (pid == 0)
{
close(listenfd);
echo_ser(conn);
exit(EXIT_SUCCESS);
} close(conn);
} return 0;
}
客户端程序cli.c程序:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h> #include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include<sys/un.h> #define ERR_EXIT(m) \
do { \
perror(m); \
exit(EXIT_FAILURE); \
} while (0) void echo_cli(int conn)
{
char sendbuf[1024] = {0};
char recvbuf[1024] = {0};
while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
{ write(conn, sendbuf, strlen(sendbuf));
read(conn, recvbuf, sizeof(recvbuf));
fputs(recvbuf, stdout);
memset(recvbuf, 0, sizeof(recvbuf));
memset(sendbuf, 0, sizeof(sendbuf));
} close(conn);
} int main(void)
{
int sock;
if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
ERR_EXIT("socket error"); struct sockaddr_un servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sun_family = AF_UNIX;
strcpy(servaddr.sun_path, "/tmp/test socket"); if (connect(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
ERR_EXIT("connect error"); echo_cli(sock); return 0;
}
server 使用fork 的形式来接受多个连接,server调用bind 会创建一个文件,如下所示:
huangcheng@ubuntu:/tmp$ ls -l test\ socket
srwxr-xr-x 1 huangcheng huangcheng 0 2013-08-02 19:30 test socket
即文件类型为s,表示SOCKET文件,与FIFO(命名管道)文件,类型为p,类似,都表示内核的一条通道,读写文件实际是在读写内核通道。程序中调用unlink 是为了在开始执行程序时删除以前创建的文件,以便在重启服务器时不会提示address in use。其他方面与以前说过的回射客户服务器程序没多大区别,不再赘述。
三、UNIX域套接字编程注意点
1、bind成功将会创建一个文件,权限为:0777 & ~umask
2、sun_path最好用一个绝对路径。
3、UNIX域协议支持流式套接口与报式套接口。
4、UNIX域流式套接字connect发现监听队列满时,会立刻返回一个ECONNREFUSED,这和TCP不同,如果监听队列满,会忽略到来的SYN,这导致对方重传SYN。
四、socketpair 函数
功能:创建一个全双工的流管道
int socketpair(int domain, int type, int protocol, int sv[2]);
参数:
- domain: 协议家族
- type: 套接字类型
- protocol:协议类型
- sv:返回套接字对
返回值:成功返回0;失败返回-1
实际上socketpair 函数跟pipe 函数是类似的,也只能在同个主机上具有亲缘关系的进程间通信,但pipe 创建的匿名管道是半双工的,而socketpair 可以认为是创建一个全双工的管道。
可以使用socketpair 创建返回的套接字对进行父子进程通信:
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h> #define ERR_EXIT(m) \
do { \
perror(m); \
exit(EXIT_FAILURE); \
} while (0) int main(void)
{
int sockfds[2]; if (socketpair(PF_UNIX, SOCK_STREAM, 0, sockfds) < 0)
ERR_EXIT("sockpair"); pid_t pid;
pid = fork();
if (pid == -1)
ERR_EXIT("fork"); if (pid > 0)
{
int val = 0;
close(sockfds[1]);
while (1)
{ ++val;
printf(" sending data: %d\n", val);
write(sockfds[0], &val, sizeof(val));
read(sockfds[0], &val, sizeof(val));
printf("recv data : %d\n", val);
sleep(1);
} } else if (pid == 0)
{ int val;
close(sockfds[0]);
while (1)
{ read(sockfds[1], &val, sizeof(val));
++val;
write(sockfds[1], &val, sizeof(val));
}
} return 0;
}
输出如下:
huangcheng@ubuntu:~$ ./a.out
sending data: 1
recv data : 2
sending data: 3
recv data : 4
sending data: 5
recv data : 6
sending data: 7
recv data : 8
sending data: 9
recv data : 10
sending data: 11
recv data : 12
sending data: 13
.............................
即父进程持有sockfds[0] 套接字进行读写,而子进程持有sockfds[1] 套接字进行读写。
UNIX网络编程——UNIX域套接字编程和socketpair 函数的更多相关文章
- UNIX域套接字编程和socketpair 函数
一.UNIX Domain Socket IPC socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket.虽然网络soc ...
- unix网络编程——TCP套接字编程
TCP客户端和服务端所需的基本套接字.服务器先启动,之后的某个时刻客户端启动并试图连接到服务器.之后客户端向服务器发送请求,服务器处理请求,并给客户端一个响应.该过程一直持续下去,直到客户端关闭,给服 ...
- 初探网络编程--TCP套接字编程演示
今天看了一下<计算机网络:自顶向下方法>,也就是计算机网络的教材的应用层一章,决定实现以下后面的Java C/S应用程序的例子,用来演示TCP和UDP套接字编程. 程序流程如下: 1.一台 ...
- C项目实践--网络协议和套接字编程
1.TCP/IP协议 TCP/IP协议是一组包括TCP协议和IP协议,UDP(User Datagram Protocol)协议,ICMP(Internet Control Message Proto ...
- Linux网络编程——原始套接字编程
原始套接字编程和之前的 UDP 编程差不多,无非就是创建一个套接字后,通过这个套接字接收数据或者发送数据.区别在于,原始套接字可以自行组装数据包(伪装本地 IP,本地 MAC),可以接收本机网卡上所有 ...
- <unix网络编程>UDP套接字编程
典型的UDP客户/服务器程序的函数调用如下: 1.缓冲区 发送缓冲区用虚线表示,任何UDP套接字都有发送缓冲区,不过该缓冲区仅能表示写到该套接字的UDP数据报的上限.如果应用进程写一个大于套接字缓冲区 ...
- 19、网络编程 (Socket套接字编程)
网络模型 *A:网络模型 TCP/IP协议中的四层分别是应用层.传输层.网络层和链路层,每层分别负责不同的通信功能,接下来针对这四层进行详细地讲解. 链路层:链路层是用于定义物理传输通道,通常是对某些 ...
- 通过UNIX域套接字传递描述符的应用
传送文件描述符是高并发网络服务编程的一种常见实现方式.Nebula 高性能通用网络框架即采用了UNIX域套接字传递文件描述符设计和实现.本文详细说明一下传送文件描述符的应用. 1. TCP服务器程 ...
- unix进程间通信方式(下)-unix域套接字(转)
在之前的博客中已经总结了其它7种进程间的通信方式.unix域套接字用于在同一台计算机上的进程间通信,虽然因特网域套接字可用于同一目的,但是unix域套接字的效率更高.unix域套接字并不进行协议处理, ...
随机推荐
- hdu 5002 (动态树lct)
Tree Time Limit: 16000/8000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submi ...
- ●BZOJ 1272 [BeiJingWc2008]Gate Of Babylon
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1272 题解: 容斥,Lucas定理本题的容斥考虑类似 [BZOJ 1042 [HAOI200 ...
- 51Nod 1482 部落信号
题目描述: 众所周知,如今的波兰在很久以前住着很多部落.他们的首都被n座山所环绕,形成一个圆圈.在每一座山上有一个哨兵,他日夜观察附近的山. 如果有任何危险,哨兵会在山上放一把火.如果在连接两座山的圆 ...
- 【UOJ UNR #1】争夺圣杯
来自FallDream的博客,未经允许,请勿转载,谢谢. 传送门 考虑直接对每个数字,统计它会产生的贡献. 单调栈求出每个数字左边第一个大等于他的数,右边第一个大于他的 (注意只能有一边取等) 假设左 ...
- [Project] Simulate HTTP Post Request to obtain data from Web Page by using Python Scrapy Framework
1. Background Though it's always difficult to give child a perfect name, parent never give up trying ...
- SpringBoot学习之集成dubbo
一.摘自官网的一段描述 1.背景 随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进. 单一应用架构 ...
- Android Activity的任务栈和四大启动模式
在安卓系统中默认每次启动一个Activity时,系统会创建一个实例,并按照先进后出的原则放入任务栈中,当我们按back键时,就会有一个activity从任务栈顶移除,重复下去,直到任务栈为空,系统就会 ...
- glusterfs 4.0.1 api 分析笔记1
一般来说,我们写个客户端程序大概的样子是这样的: /* glfs_example.c */ // gcc -o glfs_example glfs_example.c -L /usr/lib64/ - ...
- jqGrid 使用心得
参考: https://blog.csdn.net/u012411219/article/details/51315419 https://www.cnblogs.com/kissdodog/p/38 ...
- 网页底部广告悬浮弹窗(css)
有的单页面需要添加广告等悬浮div. 部分代码: <div class="flex"> 内容.... </div> 主要css代码: .flex{posit ...