标题:Unix域套接字,UNIX域套接字实例。 出处:向东博客 专注WEB应用 构架之美 --- 构架之美,在于尽态极妍 | 应用之美,在于药到病除 时间:Mon, 18 Apr 2016 14:17:00 +0000 作者:jackxiang 地址:http://jackxiang.com/post/8643/ 内容: 背景:像unix或linux下的mysql和php-fpm都有一个xxx.sock文件,它是干嘛的呢?可以研究一下它。 管道由于只能实现具有亲缘进程的进程间通信,使用受到了很大的限制,命名管道解决了这一问题。但是,无论是管道还是命名管道,都只能实现单向通信(在只创建一个管道的情况下)。 使用套接字除了可以实现网络间不同主机间的通信外,还可以实现同一主机的不同进程间的通信,且建立的通信是双向的通信。这里所指的使用套接字实现进程间通信,是由将通信域指定为PF_UNIX来实现的。该函数的形式如下: int socket(int domain, int type, int protocol); socket函数中的domain参数用于指定通信域,domain参数取PF_UNIX时,表示创建UNIX域的套接字。使用PF_UNIX域的套接字可以实现同一机器上的不同进程间的通信。 调用bind函数实现了套接字与地址(这里是文件名)的绑定。bind函数的具体信息如下: int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen); 其参数my_addr为指向结构体sockaddr_un的指针,该结构体的定义如下: #define UNIX_PATH_MAX 108 struct sockaddr_un { sa_family_t sun_family; /*PF_UNIX或AF_UNIX */ char sun_path[UNIX_PATH_MAX]; /* 路径名 */ }; 在该结构体中,sun_family为AF_UNIX。sun_path是套接字在文件系统中的路径名。 Unix域套接字是通过套接字API实现的简单的协议族。实际上它并不代表一个网络协议;它只能连接到同一台机器上的套接字。它提供了灵活的IPC机制。它的地址是它所在的文件系统的路径名,创建之后套接字就和路径名绑定在一起。用来表示Unix域地址的套接字文件能够使用stat()但是不能通过open()打开,而且应该使用套接字API对它进行操作。 Unix域套接字是面向连接的,每个套接字的连接都建立了一个新的通讯信道。服务器可能同时处理许多连接,但对于每个连接都有不同的文件描述符。这个属性使Unix域套接字能够比命名管道更好的适应IPC任务。 server.c /* ************************************************************************ * * Filename: recv.c * * Description: * * Version: 1.0 * * Created: 2011年12月03日 20时52分08秒 * * Revision: none * * Compiler: gcc * * Author: YOUR NAME (), * * Company: * * ************************************************************************/ #include #include #include #include #include #include #define PATH "/data/codesdev/testdemo/sock/server.sock" int main(int argc ,char *argv[]) { int sockfd = 0; struct sockaddr_un addr; unlink(PATH); addr.sun_family = AF_UNIX; strcpy(addr.sun_path,PATH); unsigned int len = strlen(addr.sun_path) + sizeof(addr.sun_family); sockfd = socket(AF_UNIX,SOCK_DGRAM,0); if(sockfd < 0 ) { perror("socket error"); exit(-1); } if(bind(sockfd,(struct sockaddr *)&addr,len) < 0) { perror("bind error"); close(sockfd); exit(-1); } printf("Bind is ok\n"); while(1) { char recv_buf[20] = ""; recvfrom(sockfd,recv_buf,sizeof(recv_buf),0,(struct sockaddr*)&addr,&len); printf("Recv: %s\n",recv_buf); } return 0; } send.c /* ************************************************************************ * * Filename: send.c * * Description: * * Version: 1.0 * * Created: 2011年12月03日 20时42分37秒 * * Revision: none * * Compiler: gcc * * Author: YOUR NAME (), * * Company: * * ************************************************************************/ #include #include #include #include #include #include #define PATH "/data/codesdev/testdemo/sock/server.sock" int main(int argc,char *argv[]) { int sockfd = 0; struct sockaddr_un addr; bzero(&addr,sizeof(addr)); addr.sun_family = AF_UNIX; strcpy(addr.sun_path,PATH); sockfd = socket(AF_UNIX,SOCK_DGRAM,0); if(sockfd < 0) { perror("socket error"); exit(-1); } while(1) { static int counter = 0; char send_buf[20] = ""; counter++; sprintf(send_buf,"Counter is %d",counter); int len = strlen(addr.sun_path)+sizeof(addr.sun_family); sendto(sockfd,send_buf,strlen(send_buf),0,(struct sockaddr*)&addr,len); printf("Send: %s\n",send_buf); sleep(1); } return 0; } gcc server.c -o server gcc send.c -o send [root@iZ25dcp92ckZ sock]# ./server Bind is ok 有client启动后server响应如下: Recv: Counter is 1 Recv: Counter is 2 Recv: Counter is 3 Recv: Counter is 4 [root@iZ25dcp92ckZ sock]# ./send Send: Counter is 1 Send: Counter is 2 Send: Counter is 3 Send: Counter is 4 最后,还发现那个设备文件server.sock 不能直接cat去读取,只能stat: [root@iZ25dcp92ckZ sock]# cat server.sock cat: server.sock: 没有那个设备或地址 [root@iZ25dcp92ckZ sock]# stat server.sock 文件:"server.sock" 大小:0 块:0 IO 块:4096 套接字 设备:ca01h/51713d Inode:16282 硬链接:1 权限:(0755/srwxr-xr-x) Uid:( 0/ root) Gid:( 0/ root) 最近访问:2016-04-18 14:11:20.878641353 +0800 最近更改:2016-04-18 14:11:20.878641353 +0800 最近改动:2016-04-18 14:11:20.878641353 +0800 创建时间:- 实践摘录自:http://www.cnblogs.com/hnrainll/archive/2011/12/03/2274973.html Generated by Jackxiang's Bo-blog 2.1.1 Release