unix域套接字用于服务端和客户端均位于同一台主机上进行通讯的场景,相比较通过127.0.0.1回环口的tcp,udp的优势在于效率。unix域套接字的效率提高一倍。所以很有必有了解下unix域套接字。
1.套接字基本头文件
套接字编程需要额外包含如下一些基本的头文件:
#include
头文件包含:socket,socketpair,getsockname,connect,getpeername,send,recv,
sendto,recvfrom,sendmsg,recvmsg,getsockopt,setsockopt,listen,accept,shutdown等API。
#include
#include
int inet_pton (int __af, const char *__restrict __cp,void *__restrict __buf) const char *inet_ntop (int __af, const void *__restrict __cp,char *__restrict __buf, socklen_t __len)
#include
#define __SOCKADDR_COMMON(sa_prefix) sa_family_t sa_prefix##family #define __SOCKADDR_COMMON_SIZE (sizeof (unsigned short int))
2.unix域套接字编程
unix域套接字编程和常规的tcp,udp编程使用的api完全一致,只是使用的套接字结构不一样。
ipv4上使用的是 struct sockaddr_in或者通用结构struct sockaddr,ipv6上使用的是struct sockaddr_in6或者通用结构struct sockaddr_storage,unix域使用的是struct sockaddr_un。struct sockaddr_un定义如下:
struct sockaddr_un { __SOCKADDR_COMMON (sun_); /*sun_family*/ char sun_path[108]; /* Path name. */ };
unix域套接字的domain域,必须为AF_LOCAL(AF_UNIX)
sun_path则是一个不存在的路径即可。
下面通过一个服务端和客户端的程序来说明其流程。
2.1服务端程序
/*unix域字节流套接字*/
#include
/*创建服务端*/ int main(int argc,char *argv[]) { char buf[4096]; size_t size=4096,length=0; socklen_t len=0; int sockfd=0,client_fd=0; struct sockaddr_un server_addr; struct sockaddr_un client_addr;
if(argc != 2){ printf("usage:cmd path \r\n"); return -1; }
if((sockfd=socket(AF_LOCAL,SOCK_STREAM,0))<0){ printf("socket AF_LOCAL error,errno:%d \r\n",errno); return -1; }
unlink(argv[1]); printf("sun_path:%s \r\n",argv[1]); bzero(&server_addr,sizeof(server_addr)); server_addr.sun_family = AF_LOCAL; strcpy(server_addr.sun_path,argv[1]); if(bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr))<0){ printf("bind error,errno:%d \r\n",errno); return -1; }
if(listen(sockfd,5)<0){ printf("listen error,errno:%d \r\n",errno); return -1; }
for(; ;){ len = sizeof(struct sockaddr_un); if((client_fd=accept(sockfd,(struct sockaddr *)&client_addr,&len))<0){ printf("accept error,errno:%d \r\n",errno); continue; } printf("accept fd:%d,sun_family:%d,sun_path:%s \r\n",client_fd,client_addr.sun_family,client_addr.sun_path);
while(1){ memset(buf,0,size); length = recv(client_fd,buf,size,0); if(length==0){ printf("client close the socket \r\n"); close(client_fd); client_fd = 0; break; } printf("server recv content:%s \r\n",buf); send(client_fd,buf,length,0); usleep(200000); }
}
return 0; }
2.2 客户端程序
/*unix域套接字字节流客户端*/
#include
int main(int argc,char *argv[]) { char buf[4096]; size_t size=4096; int sockfd=0; struct sockaddr_un server_adrr; struct sockaddr_un client_addr;
if(argc != 4){ printf("usage:cmd client_path server_path content\r\n"); return -1; }
if((sockfd=socket(AF_LOCAL,SOCK_STREAM,0))<0){ printf("socket AF_LOCAL error,errno:%d \r\n",errno); return -1; }
unlink(argv[1]); printf("client sun_path:%s \r\n",argv[1]); client_addr.sun_family = AF_LOCAL; strcpy(client_addr.sun_path,argv[1]); if(bind(sockfd,(struct sockaddr *)&client_addr,sizeof(struct sockaddr_un))<0){ printf("bind error,errno:%d \r\n",errno); return -1; }
printf("server sun_path:%s \r\n",argv[2]); server_adrr.sun_family = AF_LOCAL; strcpy(server_adrr.sun_path,argv[2]); if(connect(sockfd,(struct sockaddr *)&server_adrr,sizeof(struct sockaddr_un))<0){ printf("connect error,errno:%d \r\n",errno); return -1; }
printf("send content:%s \r\n",argv[3]); memset(buf,0,size); send(sockfd,argv[3],strlen(argv[3])+1,0); recv(sockfd,buf,size,0); printf("client recv content:%s \r\n",buf);
close(sockfd);
return 0; }
2.3 测试
运行服务端后的打印如下:
运行客户端,发送一段数据,服务端将数据回送给客户端,打印如下:
我们再看下服务端和客户端的path的类型,如下图:
可见 /usrdata/chengdu /usrdata/chengdu1 的类型是s,套接字类型。
我们再netstat看下unix套接字的网络状态:
由于客户端已经退出,所以服务端处于监听(listen)状态,后面的path和我们设置的值是吻合的。
好文推荐
发表评论