无聊的柚子 · 《史记·赵世家》“赵氏孤儿”故事的来源与演变· 1 年前 · |
呐喊的小蝌蚪 · Axure移动端通用元件库rplib格式包含 ...· 1 年前 · |
不拘小节的水煮鱼 · 天蝎座之夜3菲律宾英文电影名 - 抖音· 1 年前 · |
深情的烈酒 · 超赞同梦会漫画|官方在线漫画全集-快看· 1 年前 · |
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用于无聊的柚子 · 《史记·赵世家》“赵氏孤儿”故事的来源与演变 1 年前 |
呐喊的小蝌蚪 · Axure移动端通用元件库rplib格式包含安卓、苹果各种主流手机、平板线框图元件库、IOS系统图标、人物图标、导航和分页、表格元素、各种小图标、移动元件库、axure元件库、axure原型 - 知乎 1 年前 |
不拘小节的水煮鱼 · 天蝎座之夜3菲律宾英文电影名 - 抖音 1 年前 |
深情的烈酒 · 超赞同梦会漫画|官方在线漫画全集-快看 1 年前 |