添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

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