https://www.cnblogs.com/chekliang/p/3222950.html
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绑定到一个地址。
12
memset(&un,
0
,
sizeof
(un));
13
un.sun_family =
AF_UNIX;
14
strcpy(un.sun_path,
"
foo.socket
"
);
15
if
((fd = socket(AF_UNIX, SOCK_STREAM,
0
)) <
0
)
16
{
17
perror(
"
socket error
"
);
18
exit(
1
);
19
}
20
size = offsetof(
struct
sockaddr_un, sun_path) +
strlen(un.sun_path);
22
if
(bind(fd, (
struct
sockaddr *)&un, size) <
0
)
23
{
24
perror(
"
bind error
"
);
25
exit(
1
);
26
}
28
printf(
"
UNIX domain socket bound/n
"
);
29
exit(
0
);
注意程序中的offsetof宏,它在stddef.h头文件中定义:
#define offsetof(TYPE, MEMBER) ((int)&((TYPE *)0)->MEMBER)
offsetof(struct sockaddr_un, sun_path)就是取sockaddr_un结构体的sun_path成员在结构体中的偏移,也就是从结构体的第几个字节开始是sun_path成员。想一想,这个宏是如何实现这一功能的?(先将TYPE类型的指针首地址设为0,然后取MEMBER成员的地址就是该成员在TYPE中的偏移数。)
该程序的运行结果如下。
$ ./a.out UNIX domain socket bound
$ ls -l
foo.socket srwxrwxr-x 1 user 0 Aug 22 12:43 foo.socket
$ ./a.out bind error: Address already in use
$ rm foo.socket
$ ./a.out UNIX domain socket bound
以下是服务器的listen模块,与网络socket编程类似,在bind之后要listen,表示通过bind的地址(也就是socket文件)提供服务。
8
/*
9
* Create a server endpoint of a connection.
10
* Returns fd if all OK, <0 on error.
11
*/
13
int
serv_listen(
const
char
*
name)
14
{
15
int
fd, len, err, rval;
16
struct
sockaddr_un un;
18
/*
create a UNIX domain stream socket
*/
19
if
((fd = socket(AF_UNIX, SOCK_STREAM,
0
)) <
0
)
20
return
(-
1
);
21
unlink(name);
/*
in case it already exists
*/
23
/*
fill in socket address structure
*/
24
memset(&un,
0
,
sizeof
(un));
25
un.sun_family =
AF_UNIX;
27
strcpy(un.sun_path, name);
28
len = offsetof(
struct
sockaddr_un, sun_path) +
strlen(name);
30
/*
bind the name to the descriptor
*/
31
if
(bind(fd, (
struct
sockaddr *)&un, len) <
0
)
32
{
33
rval = -
2
;
34
goto
errout;
35
}
37
if
(listen(fd, QLEN) <
0
)
38
{
/*
tell kernel we're a server
*/
39
rval = -
3
;
40
goto
errout;
41
}
43
return
(fd);
45
errout:
46
err =
errno;
47
close(fd);
48
errno =
err;
49
return
(rval);
7
int
serv_accept(
int
listenfd, uid_t *
uidptr)
8
{
int
clifd, len, err, rval;
9
time_t staletime;
10
struct
sockaddr_un un;
11
struct
stat statbuf;
12
len =
sizeof
(un);
13
if
((clifd = accept(listenfd, (
struct
sockaddr *)&un, &len)) <
0
)
14
return
(-
1
);
15
/*
often errno=EINTR, if signal caught
*/
16
/*
obtain the client's uid from its calling address
*/
17
len -= offsetof(
struct
sockaddr_un, sun_path);
/*
len of pathname
*/
18
un.sun_path[len] =
0
;
/*
null terminate
*/
19
if
(stat(un.sun_path, &statbuf) <
0
)
20
{
21
rval = -
2
;
22
goto
errout;
23
}
24
if
(S_ISSOCK(statbuf.st_mode) ==
0
)
25
{
26
rval = -
3
;
27
/*
not a socket
*/
28
goto
errout;
29
}
30
if
(uidptr !=
NULL)
31
*uidptr = statbuf.st_uid;
/*
return uid of caller
*/
32
unlink(un.sun_path);
/*
we're done with pathname now
*/
34
return
(clifd);
36
errout:
37
err =
errno;
38
close(clifd);
39
errno =
err;
40
return
(rval);
16
/*
+5 for pid = 14 chars
*/
17
/*
18
* Create a client endpoint and connect to a server.
19
* Returns fd if all OK, <0 on error.
20
*/
21
int
cli_conn(
const
char
*
name)
22
{
23
int
fd, len, err, rval;
24
struct
sockaddr_un un;
25
/*
create a UNIX domain stream socket
*/
26
if
((fd = socket(AF_UNIX, SOCK_STREAM,
0
)) <
0
)
27
return
(-
1
);
/*
fill socket address structure with our address
*/
28
memset(&un,
0
,
sizeof
(un));
29
un.sun_family =
AF_UNIX;
30
sprintf(un.sun_path,
"
%s%05d
"
, CLI_PATH, getpid());
31
len = offsetof(
struct
sockaddr_un, sun_path) +
strlen(un.sun_path);
32
unlink(un.sun_path);
33
/*
in case it already exists
*/
34
if
(bind(fd, (
struct
sockaddr *)&un, len) <
0
)
35
{
36
rval = -
2
;
37
goto
errout;
38
}
39
/*
fill socket address structure with server's address
*/
40
memset(&un,
0
,
sizeof
(un));
41
un.sun_family =
AF_UNIX;
42
strcpy(un.sun_path, name);
43
len = offsetof(
struct
sockaddr_un, sun_path) +
strlen(name);
44
if
(connect(fd, (
struct
sockaddr *)&un, len) <
0
)
45
{
46
rval = -
4
;
47
goto
errout;
48
}
return
(fd);
49
errout: err =
errno;
50
close(fd);
51
errno =
err;
52
return
(rval);
#define
MAX_CONNECTION_NUMBER 5
/*
* Create a server endpoint of a connection. * Returns fd if all OK, <0 on error.
*/
int
unix_socket_listen(
const
char
*
servername)
int
fd;
struct
sockaddr_un un;
if
((fd = socket(AF_UNIX, SOCK_STREAM,
0
)) <
0
)
return
(-
1
);
int
len, rval;
unlink(servername);
/*
in case it already exists
*/
memset(
&un,
0
,
sizeof
(un));
un.sun_family
=
AF_UNIX;
strcpy(un.sun_path, servername);
len
= offsetof(
struct
sockaddr_un, sun_path) +
strlen(servername);
/*
bind the name to the descriptor
*/
if
(bind(fd, (
struct
sockaddr *)&un, len) <
0
)
rval
= -
2
;
if
(listen(fd, MAX_CONNECTION_NUMBER) <
0
)
rval
= -
3
;
return
fd;
int
err;
err
=
errno;
close(fd);
errno
=
err;
return
rval;
int
unix_socket_accept(
int
listenfd, uid_t *
uidptr)
int
clifd, len, rval;
time_t staletime;
struct
sockaddr_un un;
struct
stat statbuf;
len
=
sizeof
(un);
if
((clifd = accept(listenfd, (
struct
sockaddr *)&un, &len)) <
0
)
return
(-
1
);
/*
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
;
if
(S_ISSOCK(statbuf.st_mode) )
if
(uidptr != NULL) *uidptr = statbuf.st_uid;
/*
return uid of caller
*/
unlink(un.sun_path);
/*
we're done with pathname now
*/
return
clifd;
rval
= -
3
;
/*
not a socket
*/
int
err;
err
=
errno;
close(clifd);
errno
=
err;
return
(rval);
void
unix_socket_close(
int
fd)
close(fd);
int
main(
void
)
int
listenfd,connfd;
listenfd
= unix_socket_listen(
"
foo.sock
"
);
if
(listenfd<
0
)
printf(
"
Error[%d] when listening...\n
"
,errno);
return
0
;
printf(
"
Finished listening...\n
"
,errno);
uid_t uid;
connfd
= unix_socket_accept(listenfd, &
uid);
unix_socket_close(listenfd);
if
(connfd<
0
)
printf(
"
Error[%d] when accepting...\n
"
,errno);
return
0
;
printf(
"
Begin to recv/send...\n
"
);
int
i,n,size;
char
rvbuf[
2048
];
for
(i=
0
;i<
2
;i++
)
//
===========接收==============
size = recv(connfd, rvbuf,
804
,
0
);
if
(size>=
0
)
//
rvbuf[size]='\0';
printf(
"
Recieved Data[%d]:%c...%c\n
"
,size,rvbuf[
0
],rvbuf[size-
1
]);
if
(size==-
1
)
printf(
"
Error[%d] when recieving Data:%s.\n
"
,errno,strerror(errno));
break
;
//===========发送==============
memset(rvbuf, 'c', 2048);
size = send(connfd, rvbuf, 2048, 0);
if(size>=0)
printf("Data[%d] Sended.\n",size);
if(size==-1)
printf("Error[%d] when Sending Data.\n",errno);
break;
sleep(
30
);
unix_socket_close(connfd);
printf(
"
Server exited.\n
"
);
7
#include <
string
.h>
9
/*
Create a client endpoint and connect to a server. Returns fd if all OK, <0 on error.
*/
10
int
unix_socket_conn(
const
char
*
servername)
11
{
12
int
fd;
13
if
((fd = socket(AF_UNIX, SOCK_STREAM,
0
)) <
0
)
/*
create a UNIX domain stream socket
*/
14
{
15
return
(-
1
);
16
}
17
int
len, rval;
18
struct
sockaddr_un un;
19
memset(&un,
0
,
sizeof
(un));
/*
fill socket address structure with our address
*/
20
un.sun_family =
AF_UNIX;
21
sprintf(un.sun_path,
"
scktmp%05d
"
, getpid());
22
len = offsetof(
struct
sockaddr_un, sun_path) +
strlen(un.sun_path);
23
unlink(un.sun_path);
/*
in case it already exists
*/
24
if
(bind(fd, (
struct
sockaddr *)&un, len) <
0
)
25
{
26
rval= -
2
;
27
}
28
else
29
{
30
/*
fill socket address structure with server's address
*/
31
memset(&un,
0
,
sizeof
(un));
32
un.sun_family =
AF_UNIX;
33
strcpy(un.sun_path, servername);
34
len = offsetof(
struct
sockaddr_un, sun_path) +
strlen(servername);
35
if
(connect(fd, (
struct
sockaddr *)&un, len) <
0
)
36
{
37
rval= -
4
;
38
}
39
else
40
{
41
return
(fd);
42
}
43
}
44
int
err;
45
err =
errno;
46
close(fd);
47
errno =
err;
48
return
rval;
49
}
51
void
unix_socket_close(
int
fd)
52
{
53
close(fd);
54
}
57
int
main(
void
)
58
{
59
srand((
int
)time(
0
));
60
int
connfd;
61
connfd = unix_socket_conn(
"
foo.sock
"
);
62
if
(connfd<
0
)
63
{
64
printf(
"
Error[%d] when connecting...
"
,errno);
65
return
0
;
66
}
67
printf(
"
Begin to recv/send...\n
"
);
68
int
i,n,size;
69
char
rvbuf[
4096
];
70
for
(i=
0
;i<
10
;i++
)
71
{
72
/*
73
//=========接收=====================
74
size = recv(connfd, rvbuf, 800, 0); //MSG_DONTWAIT
75
if(size>=0)
76
{
77
printf("Recieved Data[%d]:%c...%c\n",size,rvbuf[0],rvbuf[size-1]);
78
}
79
if(size==-1)
80
{
81
printf("Error[%d] when recieving Data.\n",errno);
82
break;
83
}
84
if(size < 800) break;
85
*/
86
//
=========发送======================
87
memset(rvbuf,
'
a
'
,
2048
);
88
rvbuf[
2047
]=
'
b
'
;
89
size = send(connfd, rvbuf,
2048
,
0
);
90
if
(size>=
0
)
91
{
92
printf(
"
Data[%d] Sended:%c.\n
"
,size,rvbuf[
0
]);
93
}
94
if
(size==-
1
)
95
{
96
printf(
"
Error[%d] when Sending Data:%s.\n
"
,errno,strerror(errno));
97
break
;
98
}
99
sleep(
1
);
100
}
101
unix_socket_close(connfd);
102
printf(
"
Client exited.\n
"
);
103
}
参考链接:
http://blog.csdn.net/guxch/article/details/7041052
原文 https://www.cnblogs.com/chekliang/p/3222950.htmlsocket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket。虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是UNIX Domain Socket用于
进程
间
通信
-
Socket
socket
是一种借口技术,可以让
不同
的
进程
进行同行,有两种
通信
方式
既可以是同一个计算机上的
进程
,也可以是
不同
计算机上的
进程
。
同一计算机的
进程
通信
需要借助
socket
的文件,进行
通信
#include <sys/types.h>
#include <sys/
socket
.h>
int
socket
(int
domain
, int type, int protocol);
功能:创建
socket
对象
为了
实现
dm365中 write 子线程能够向 live555的doGetNextFrame( ) 传递 NALU 。
dm365中的 encode 程序是基于多线程的,而 live555 是基于 select 查询机制的,为了
实现
encode 后的数据传入 live555,并经由 live555 封装 RTP 包发送。
实现
数据的交互,这成为了自己需要思考的问题。
在《嵌入式
使用
socket
实现
进程
间
通信
:(
UNIX
domain
中面向连接
通信
)
使用套接字除了可以
实现
网络
间
不同
主机
间
的
通信
外,还可以
实现
同一
主机
的
不同
进程
间
的
通信
,且建立的
通信
是双向的
通信
。
man
unix
内容如下:
NAME( 名称)
unix
, PF_
UNIX
, AF_
UNIX
, PF_LOCAL, AF_LOCAL ? 用于本地内部
进程
通讯的套接 字。
SYNOP