进程间通信之UNIX域套接字(UDS)

UNIX域套接字(UDS):UNIX Domain Socket
        UNIX域socket实现本地进程间通信,需要一个进程作为服务器端,一个进程作为客户端,使用方法有点像socket网络,但又不经过网络底层的那些东西。与网络编程最不一样的地方是服务器端bind的时候用的是sockaddr_un结构,客户端connect的时候用的也是sockaddr_un结构,而不是sockaddr_in或sockaddr。而对于sockaddr_un结构,重点是给它提供一个bind()函数生成的socket类型文件的路径,即sockaddr_un.sun_path的值。并且客户端与服务器端的这个sockaddr_un结构的sun_path是一致的,通常这个路径是众所众知的,就像百度的域名那样。

        经过bind,listen,accept,和connect后,两进程就通过读写socket文件描述符来通信,具体是服务器端读写accept返回的socket文件描述符,客户端读写经过connect处理后的文件描述符。

使用流程分析:
一、服务器端通信过程分析
服务器端基本遵循面向连接的socket数据流通信过程。
1、调用socket()函数,建立socket对象,指定通信协议为AF_UNIX。
2、调用bind()函数,将创建的socket对象与bind()函数产生的那个socket类型的文件server_socket P绑定。
        UNIX Domain Socket与网络socket编程最明显的不同在于地址格式不同,其地址用结构体sockaddr_un表示, 网络编程的socket地址是IP地址加端口号,而UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径,这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,且已被link,则bind()错误返回。一个套接字只能绑定到一个路径上,同样的,一个路径也只能被一个套接字绑定。 
        sockaddr_un结构的sun_path成员包含一路径名,当我们将一地址绑定至UNIX域套接字时,系统用该路径名创建一类型为S_IFSOCK的文件。该文件仅用于向客户端进程告知套接字名字,该文件不能打开,也不能由应用程序用于通信,当关闭套接字时,并不自动删除该文件,所以我们必须确保在应用程序终止前,对该文件执行解除链接操作(unlink(path)),或删除该文件。
        struct sockaddr_un结构有两个参数:sun_family、sun_path。sun_family只能是AF_LOCAL或AF_UNIX;而sun_path就是本地文件的路径。
3、调用listen()函数,使socket对象处于监听状态,并设置监听队列大小。
4、服务器端监听到该请求,在客户端发出请求后,accept()函数接收请求,返回新文件描述符,从而建立连接。
5、服务器端调用()函数接收数据(开始处于阻塞状态,等待客户端发送数据,因此,客户端在编程是需要首先发送数据,接收到数据后,输出接收到的数据)。
6、调用write()函数发送数据到客户端。
7、通信完成后,调用close()函数关闭socket对象;unlink(sockaddr_un.sun_path)。

二、客户端通信过程分析
客户端基本遵循面向连接的socket数据流通信过程。
1、调用socket()函数,建立socket对象,指定相同通信协议。
2、客户端调用connect()函数,向服务器端发起连接请求。
3、在得到服务器端允许后,首先调用write()函数向服务器端发送消息(因服务器端循环体中首先是接收数据)。
4、调用read()函数接收数据。
5、通信完成后,调用close()函数关闭socket对象。

具体使用例子:
这一例子实现一端发送字符,一端发送字符串。
服务器端源码:

socket_local_server.c:

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
	int server_sockfd, client_sockfd;
	int server_len, client_len;
	struct sockaddr_un server_address;
	struct sockaddr_un client_address;
	int i,byte;
	char ch_send,recv_buf[128];
	
	unlink("server_socket");	//解除原有server_socket对象链接
	server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);//创建socket,指定通信协议为AF_UNIX,数据方式SOCK_STREAM
	//配置server_address
	server_address.sun_family = AF_UNIX;
	strcpy(server_address.sun_path, "server_socket");
	server_len = sizeof(server_address);
	
	bind(server_sockfd, (struct sockaddr *)&server_address, server_len);

	listen(server_sockfd, 5);
	
	printf("server waiting for  client connect\n");
	client_len = sizeof(client_address);
	//accept函数接收客户端求情,存储客户端地址信息、客户端地址大小
	client_sockfd = accept(server_sockfd,(struct sockaddr *)&client_address, (socklen_t *)&client_len);
	printf("the server wait form client data\n");
	  
	for(i=0,ch_send='1';i<5;i++,ch_send++)
	{
		//从client_sockfd读取客户端发来的消息
		if((byte=read(client_sockfd, recv_buf, sizeof(recv_buf)))==-1)
		{
			perror("read");
			exit(EXIT_FAILURE);
		}
		printf("the massage receiver from client is: %s\n",recv_buf);
		sleep(1);
		//向客户端发送消息
		if((byte=write(client_sockfd,&ch_send,1))==-1)
		{
		   	perror("write");
			exit(EXIT_FAILURE);
		}
    }
	close(client_sockfd);
	unlink("server socket");
}

客户端源码:

socket_local_client.c:

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
	int sockfd;
	int len;
	struct sockaddr_un address;
	int result;
	int i,byte;
	char send_buf[128],ch_recv;

	if((sockfd = socket(AF_UNIX, SOCK_STREAM, 0))==-1)//创建socket,指定通信协议为AF_UNIX,数据方式SOCK_STREAM
	{
		perror("socket");
		exit(EXIT_FAILURE);
	}
	
	//配置server_address
	address.sun_family = AF_UNIX;
	strcpy(address.sun_path, "server_socket");
	len = sizeof(address);

	result = connect(sockfd, (struct sockaddr *)&address, len);

	if(result == -1) 
	{
		printf("ensure the server is up\n");
        	perror("connect");
        	exit(EXIT_FAILURE);
    	}
	for(i=0;i<5;i++)
	{
		sprintf(send_buf,"client massage %d",i);//用sprintf事先把消息写到send_buf
		if((byte=write(sockfd, send_buf, sizeof(send_buf)))==-1)
		{
			perror("write");
			exit(EXIT_FAILURE);
		}
		if((byte=read(sockfd,&ch_recv,1))==-1)
		{
			perror("read");
			exit(EXIT_FAILURE);
		}
		printf("receive from server data is: %c\n",ch_recv);
	}	
	close(sockfd);
    return 0;
}
运行结果:
服务器端:
book@book-desktop:~/workspace/zongde/chapter17$ ./socket_local_server
server waiting for  client connect
the server wait form client data
the massage receiver from client is: client massage 0
the massage receiver from client is: client massage 1
the massage receiver from client is: client massage 2
the massage receiver from client is: client massage 3
the massage receiver from client is: client massage 4
book@book-desktop:~/workspace/zongde/chapter17$ 

客户端:
book@book-desktop:~/workspace/zongde/chapter17$ ./socket_local_client
receive from server data is: 1
receive from server data is: 2
receive from server data is: 3
receive from server data is: 4
receive from server data is: 5
book@book-desktop:~/workspace/zongde/chapter17$ 

猜你喜欢

转载自blog.csdn.net/qq_22863733/article/details/80629920