网络编程一<线程间通信的方法之UNIX域套接字>

来源:互联网 发布:mac系统官方下载地址 编辑:程序博客网 时间:2024/06/10 08:37

socket API原本是为网络通讯设计的,后来在socket的框架上发展出一种IPC机制,就是UNIX Domain Socket

虽然网络socket也可用于同一台主机的进程间通讯,但是UNIX Domain Socket用于IPC更有效率不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程

UNIX域套接字与TCP套接字相比较,在同一台主机的传输速度前者是后者的两倍。IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。UNIX Domain Socket也提供面向流面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIXDomain Socket也是可靠的,消息既不会丢失也不会顺序错乱。

我们先来看下地址格式:

<span style="font-family:FangSong_GB2312;font-size:18px;">struct sockaddr_un {        sa_family_t sun_family;      /* AF_UNIX */        char        sun_path[108];   /* pathname */   };</span>

UNIX Domain Socket与因特网域套接字socket编程最明显的不同在于地址格式不同,用结构体sockaddr_un表示,因特网域套接字socket地址是IP地址加端口号,而UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径。

创建套接字的函数如下:

<span style="font-family:FangSong_GB2312;font-size:18px;">#include <sys/socket.h>  int socket(int domain, int type, int protocol);/*成功返回文件(套接字)描述符,出错返回-1*/ </span>

其中的domain参数用于指定通信域,如果为PF_UNIX的话,那么创建unix域套接字,type套接字类型主要有面向连接的字节流SOCK_STREAM和长度固定的无连接的不可靠数据报报文传递SOCK_DGRAM。参数protocol通常为0。

下面有两组代码(第一组type为SOCK_STREAM的服务端和客户端,第二组为SOCK_DGRAM)。

第一组server.c:

#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/un.h> #define UNIX_DOMAIN "UNIX.domain"int main(void){    socklen_t clt_addr_len;    int listen_fd;    int com_fd;    int ret;    int i;    static char recv_buf[1024];     int len;    struct sockaddr_un clt_addr;    struct sockaddr_un srv_addr;    listen_fd=socket(PF_UNIX,SOCK_STREAM,0);    if(listen_fd<0)    {        perror("cannot create communication socket");        return 1;    }          //set server addr_param    srv_addr.sun_family=AF_UNIX;    strncpy(srv_addr.sun_path,UNIX_DOMAIN,sizeof(srv_addr.sun_path)-1);    unlink(UNIX_DOMAIN);    //bind sockfd & addr    ret=bind(listen_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));    if(ret==-1)    {        perror("cannot bind server socket");        close(listen_fd);        unlink(UNIX_DOMAIN);        return 1;    }    //listen sockfd     ret=listen(listen_fd,1);    if(ret==-1)    {        perror("cannot listen the client connect request");        close(listen_fd);        unlink(UNIX_DOMAIN);        return 1;    }    //have connect request use accept    len=sizeof(clt_addr);    com_fd=accept(listen_fd,(struct sockaddr*)&clt_addr,&len);    if(com_fd<0)    {        perror("cannot accept client connect request");        close(listen_fd);        unlink(UNIX_DOMAIN);        return 1;    }    //read and printf sent client info    printf("/n=====info=====/n");    for(i=0;i<4;i++)    {        memset(recv_buf,0,1024);        int num=read(com_fd,recv_buf,sizeof(recv_buf));        printf("Message from client (%d)) :%s/n",num,recv_buf);      }    close(com_fd);    close(listen_fd);    unlink(UNIX_DOMAIN);    return 0;}
client.c:

#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/un.h>#define UNIX_DOMAIN "UNIX.domain"int main(void){    int connect_fd;    int ret;    char snd_buf[1024];    int i;    static struct sockaddr_un srv_addr;//creat unix socket    connect_fd=socket(PF_UNIX,SOCK_STREAM,0);    if(connect_fd<0)    {        perror("cannot create communication socket");        return 1;    }       srv_addr.sun_family=AF_UNIX;    strcpy(srv_addr.sun_path,UNIX_DOMAIN);//connect server    ret=connect(connect_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));    if(ret==-1)    {        perror("cannot connect to the server");        close(connect_fd);        return 1;    }    memset(snd_buf,0,1024);    strcpy(snd_buf,"message from client");//send info server    for(i=0;i<4;i++)        write(connect_fd,snd_buf,sizeof(snd_buf));    close(connect_fd);    return 0;}

第二组server.c:

/* * Demo how to implement a simple Local server */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/un.h>#define MAXLINE 50#define IPC_PATH "unix_local_socket"typedef struct sockaddr SA;int main(int argc, char **argv){        intsockfd;struct sockaddr_un  local_addr, remote_addr;socklen_tremote_len;charbuf_rcv[MAXLINE];ssize_trcvlen;charbuf_snd[MAXLINE] = "Welcome to UDP Server";        /* step1: create socket * note the socket is creaed as type of SOCK_DGRAM to * work in UDP  */if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {perror("socket failed");exit(-1);}/* unlink may return error when the file does not exist, so * we just ignore the return value */       unlink(IPC_PATH);/* step2: bind the sockect to */bzero(&local_addr, sizeof(local_addr));local_addr.sun_family      = AF_UNIX;strcpy (local_addr.sun_path, IPC_PATH);if (bind(sockfd, (SA *) &local_addr, sizeof(local_addr)) < 0) {perror("bind failed");exit(-1);}remote_addr = local_addr;for (;;) {/* step3: recvfrom */bzero(buf_rcv, sizeof(buf_rcv)); /* clean up buffer to receive data */remote_len = sizeof(remote_addr);if ((rcvlen = recvfrom(sockfd, buf_rcv, sizeof(buf_rcv), 0, NULL, NULL)) < 0) {perror("recvfrom failed");exit(-1);}if (rcvlen == MAXLINE) buf_rcv[MAXLINE-1] = 0x00; /* in case of overflow */printf("recvfrom successed: %s\n", buf_rcv);break; /* break when receive the data from the client */}return 0;}

client.c:

/* * Demo how to implement a simple Local client */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/un.h>#define MAXLINE 50#define IPC_PATH "unix_local_socket"typedef struct sockaddr SA;int main(int argc, char **argv){        intsockfd, nbyte;structsockaddr_un  remote_addr;charbuf_snd[MAXLINE] = "Hello from UDP client";/* step1: create socket * note the socket is creaed as type of SOCK_DGRAM to * work in UDP  */     if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {perror("socket failed");exit(-1);}/* step2: directly send w/o bind */bzero(&remote_addr, sizeof(remote_addr));remote_addr.sun_family      = AF_UNIX;strcpy (remote_addr.sun_path, IPC_PATH);if (-1 == sendto(sockfd, buf_snd, sizeof(buf_snd), 0, (SA *)&remote_addr, sizeof(remote_addr))) {perror("sendto failed");exit(-1);}printf("C> recvfrom begin ...\n");             if ((nbyte = recvfrom(sockfd, buf, MAXLINE, 0, NULL, NULL)) < 0) {perror("C> recvfrom error");exit(-1);}return 0;}


0 0