Domain Socket本地进程间通信

摘要:
socketAPI原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIXDomainSocket。UNIXDomainSocket也提供面向流和面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIXDomainSocket也是可靠的,消息既不会丢失也不会顺序错乱。UNIXDomainSocket是全双工的,API接口语义丰富,相比其它IPC机制有明显的优越性,目前已成为使用最广泛的IPC机制,比如XWindow服务器和GUI程序之间就是通过UNIXDomainSocket通讯的。以下程序将UNIXDomainsocket绑定到一个地址。

socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机
制,就是UNIX Domain Socket。虽然网络socket也可用于同一台主机的进程间通讯(通过
loopback地址127.0.0.1),但是UNIX Domain Socket用于IPC更有效率:不需要经过网络协
议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷
贝到另一个进程。这是因为,IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯
设计的。UNIX Domain Socket也提供面向流和面向数据包两种API接口,类似于TCP和UDP,
但是面向消息的UNIX Domain Socket也是可靠的,消息既不会丢失也不会顺序错乱。
UNIX Domain Socket是全双工的,API接口语义丰富,相比其它IPC机制有明显的优越
性,目前已成为使用最广泛的IPC机制,比如X Window服务器和GUI程序之间就是通过UNIX
Domain 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()错误返回。
以下程序将UNIX Domain socket绑定到一个地址。

Domain Socket本地进程间通信第1张

size = offsetof(struct sockaddr_un, sun_path) +strlen(un.sun_path);
#define offsetof(TYPE, MEMBER) ((int)&((TYPE *)0)->MEMBER)

server

#include <stdlib.h>#include <stdio.h>#include <stddef.h>#include <sys/socket.h>#include <sys/un.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <errno.h>
#define QLEN 10
/** Create a server endpoint of a connection.
* Returns fd if all OK, <0 on error.
*/
int serv_listen(const char *name)
{
intfd, len, err, rval;
structsockaddr_un un;
/*create a UNIX domain stream socket */
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
return(-1);
unlink(name); /*in case it already exists 否则bind的时候会出错*/
/*fill in socket address structure */memset(&un, 0, sizeof(un));
un.sun_family =AF_UNIX;
strcpy(un.sun_path, name);
len = offsetof(struct sockaddr_un, sun_path) +strlen(name);
/*bind the name to the descriptor 会创建name*/
if (bind(fd, (struct sockaddr *)&un, len) < 0) {
rval = -2;
gotoerrout;
}
if (listen(fd, QLEN) < 0) { /*tell kernel we're a server */rval = -3;
gotoerrout;
}
return(fd);
errout:
err =errno;
close(fd);
errno =err;
return(rval);
}
int serv_accept(int listenfd, uid_t *uidptr)
{
intclifd, len, err, rval;
time_t staletime;
structsockaddr_un un;
structstat statbuf;
len = sizeof(un);
if ((clifd = accept(listenfd, (struct sockaddr *)&un, &len)) < 0)
return(-1); /*often errno=EINTR, if signal caught */
/*obtain the client's uid from its calling address */len -= offsetof(struct sockaddr_un, sun_path); /*len of pathname */un.sun_path[len] = 0; /*null terminate */
if (stat(un.sun_path, &statbuf) < 0) {
rval = -2;
gotoerrout;
}
if (S_ISSOCK(statbuf.st_mode) == 0) {
rval = -3; /*not a socket */
gotoerrout;
}
if (uidptr !=NULL)
*uidptr = statbuf.st_uid; /*return uid of caller */unlink(un.sun_path); /*we're done with pathname now */
return(clifd);
errout:
err =errno;
close(clifd);
errno =err;
return(rval);
}
int main(void)
{
intlfd, cfd, n, i;
uid_t cuid;
char buf[1024];
lfd = serv_listen("foo.socket");
if (lfd < 0) {
switch(lfd) {
case -3:perror("listen"); break;
case -2:perror("bind"); break;
case -1:perror("socket"); break;
}
exit(-1);
}
cfd = serv_accept(lfd, &cuid);
if (cfd < 0) {
switch(cfd) {
case -3:perror("not a socket"); break;
case -2:perror("a bad filename"); break;
case -1:perror("accept"); break;
}
exit(-1);
}
while (1) {
r_again:
n = read(cfd, buf, 1024);
if (n == -1) {
if (errno ==EINTR)
gotor_again;
}
else if (n == 0) {
printf("the other side has been closed.
");
break;
}
for (i = 0; i < n; i++)
buf[i] =toupper(buf[i]);
write(cfd, buf, n);
}
close(cfd);
close(lfd);
return 0;
}

client

#include <stdio.h>#include <stdlib.h>#include <stddef.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <sys/socket.h>#include <sys/un.h>#include <errno.h>
#define CLI_PATH "/var/tmp/" /* +5 for pid = 14 chars */
/** Create a client endpoint and connect to a server.
* Returns fd if all OK, <0 on error.
*/
int cli_conn(const char *name)
{
intfd, len, err, rval;
structsockaddr_un un;
/*create a UNIX domain stream socket */
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
return(-1);
/*fill socket address structure with our address */memset(&un, 0, sizeof(un));
un.sun_family =AF_UNIX;
sprintf(un.sun_path, "%s%05d", CLI_PATH, getpid());
len = offsetof(struct sockaddr_un, sun_path) +strlen(un.sun_path);
unlink(un.sun_path); /*in case it already exists */
if (bind(fd, (struct sockaddr *)&un, len) < 0) {
rval = -2;
gotoerrout;
}
/*fill socket address structure with server's address */memset(&un, 0, sizeof(un));
un.sun_family =AF_UNIX;
strcpy(un.sun_path, name);
len = offsetof(struct sockaddr_un, sun_path) +strlen(name);
if (connect(fd, (struct sockaddr *)&un, len) < 0) {
rval = -4;
gotoerrout;
}
return(fd);
errout:
err =errno;
close(fd);
errno =err;
return(rval);
}
int main(void)
{
intfd, n;
char buf[1024];
fd = cli_conn("foo.socket");
if (fd < 0) {
switch(fd) {
case -4:perror("connect"); break;
case -3:perror("listen"); break;
case -2:perror("bind"); break;
case -1:perror("socket"); break;
}
exit(-1);
}
while (fgets(buf, sizeof(buf), stdin) !=NULL) {
write(fd, buf, strlen(buf));
n = read(fd, buf, sizeof(buf));
write(STDOUT_FILENO, buf, n);
}
close(fd);
return 0;
}

免责声明:文章转载自《Domain Socket本地进程间通信》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇浅析exports和module.exports的理解div包裹页面后多余部分没有显示,也没滚动条 overflow 属性设置下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

[Linux] 多进程网络编程监听一个端口

SO_REUSEPORT支持多个进程或者线程绑定到同一端口 每个进程可以自己创建socket、bind、listen、accept相同的地址和端口,各自是独立平等的。让多进程监听同一个端口,各个进程中accept socket fd不一样,有新连接建立时,内核只会唤醒一个进程来accept,并且保证唤醒的均衡性 <?php $context=str...

Java AES加密解密工具 -- GUI 、在线传输文件

原理 对于任意长度的明文,AES首先对其进行分组,每组的长度为128位。分组之后将分别对每个128位的明文分组进行加密。 对于每个128位长度的明文分组的加密过程如下: (1)将128位AES明文分组放入状态矩阵中。 (2)AddRoundKey变换:对状态矩阵进行AddRoundKey变换,与膨胀后的密钥进行异或操作(密钥膨胀将在实验原理七中详细讨论)。...

从网络I/O模型到Netty,先深入了解下I/O多路复用

微信搜索【阿丸笔记】,关注Java/MySQL/中间件各系列原创实战笔记,干货满满。 本文是Netty系列第3篇 上一篇文章我们了解了Unix标准的5种网络I/O模型,知道了它们的核心区别与各自的优缺点。尤其是I/O多路复用模型,在高并发场景下,有着非常好的优势。而Netty也采用了I/O多路复用模型。 那Netty是如何实现I/O多路复用的呢? Nett...

修改unix服务器时间

如果只是需要修改时间 使用date -s 12:00:00即可,改动是即时的。 CODE: # dateThu Dec 16 12:00:00 CST 2010 注意后面的“CST”为时区,修改时区有几种方法。 假如不想重启的话,可以考虑修改bash环境,首先看一看,有没有这个TZ(timezone)变量。 #env |grep TZ 没有,很干净。 #c...

【go】go语言socket通信样例

server.go package main import ( "net" "fmt" "io" ) const RECV_BUF_LEN = 1024 func main() { listener, err := net.Listen("tcp", "0.0.0.0:6666")//侦听在6666端口...

KnockoutJs官网教程学习(一)

这一教程中你将会体验到一些用knockout.js和Model-View-ViewModel(MVVM)模式去创建一个Web UI的基础方式。 将学会如何用views(视图)和declarative bindings(声明的绑定信息)去定义一个UI的展现方式,它的数据和行为使用的ViewModels(视图模型)和observables(观测),以及如何一切...