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

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)
{        
	int			sockfd;
	struct sockaddr_un  	local_addr, remote_addr;
	socklen_t		remote_len;
	char			buf_rcv[MAXLINE];
	ssize_t			rcvlen;
	char			buf_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)
{        
	int	sockfd, nbyte;
	struct	sockaddr_un  remote_addr;
	char	buf_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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值