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 头文件包含:如下常用的宏定义以及结构定义 typedef uint32_t in_addr_t; #define INADDR_ANY     ((in_addr_t) 0x00000000) #define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } struct in_addr struct in6_addr struct sockaddr_in struct sockaddr_in6

#include 头文件包含:如下常用见地址转换接口 in_addr_t inet_addr (const char *__cp)  int inet_aton (const char *__cp, struct in_addr *__inp) char *inet_ntoa (struct in_addr __in)

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 头文件包含:unix域结构 /* Structure describing the address of an AF_LOCAL (aka AF_UNIX) socket.  */ struct sockaddr_un {     __SOCKADDR_COMMON (sun_);          /*sun_family*/     char sun_path[108];        /* Path name.  */ };

#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 #include #include #include #include #include #include #include #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 #include #include #include #include #include #include #include #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和我们设置的值是吻合的。

好文推荐

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。