进程间通信之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、服务器端调用read()函数接收数据(开始处于阻塞状态,等待客户端发送数据,因此,客户端在编程是需要首先发送数据,接收到数据后,输出接收到的数据)。
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$ 

  • 7
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux 进程间通讯指的是在 Linux 操作系统中不同进程间进行数据交换的方式。在 Linux 中,有多种进程间通讯的方式,如管道、消息队列、信号量、共享内存等。 UDS (Unix Domain Socket) 是一种在单一主机上通讯的套接字,它允许同一台主机上的进程进行通讯,而不需要网络协议栈的支持。UDS 具有较高的效率和低的开销。 以下是一份基于 UDS 的简单通讯代码: ``` #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #define SOCK_PATH "echo_socket" int main(void) { int s, s2, len; unsigned t; struct sockaddr_un local, remote; char str[100]; if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } local.sun_family = AF_UNIX; strcpy(local.sun_path, SOCK_PATH); unlink(local.sun_path); len = strlen(local.sun_path) + sizeof(local.sun_family); if (bind(s, (struct sockaddr *)&local, len) == -1) { perror("bind"); exit(1); } if (listen(s, 5) == -1) { perror("listen"); exit(1); } for(;;) { int done, n; printf("Waiting for a connection...\n"); t = sizeof(remote); if ((s2 = accept(s, (struct sockaddr *)&remote, &t)) == -1) { perror("accept"); exit(1); } printf("Connected.\n"); done = 0; do { n = recv(s2, str, 100, 0); if (n <= 0) { if (n < 0) perror("recv"); done = 1; } if (!done) if (send ### 回答2: 在Linux操作系统中,进程间通讯(IPC)是指不同进程之间进行信息交换和共享资源的机制。其中一种常见的IPC方式是使用Unix Domain SocketUds)进行通讯。 Uds是一种特殊的套接字,用于在同一台机器上的进程间进行通讯。与网络套接字不同,Uds不需要通过网络进行数据传输,因此可以提供更高的性能和更低的延迟。 以下是一段简述了Uds通讯的代码示例: ```c // 进程A代码 #include <sys/socket.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/un.h> int main() { int sockfd; struct sockaddr_un addr; // 创建套接字 sockfd = socket(AF_UNIX, SOCK_STREAM, 0); // 设置套接字地址 memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, "socket_path", sizeof(addr.sun_path) - 1); // 绑定套接字 bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)); // 监听套接字 listen(sockfd, 5); // 接受连接请求 int connect_fd = accept(sockfd, NULL, NULL); // 发送数据 char buffer[1024] = "Hello from Process A"; write(connect_fd, buffer, strlen(buffer)); // 关闭套接字 close(connect_fd); close(sockfd); return 0; } ``` ```c // 进程B代码 #include <sys/socket.h> #include <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/un.h> int main() { int sockfd; struct sockaddr_un addr; // 创建套接字 sockfd = socket(AF_UNIX, SOCK_STREAM, 0); // 设置套接字地址 memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path, "socket_path", sizeof(addr.sun_path) - 1); // 连接到套接字 connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)); // 接收数据 char buffer[1024]; read(sockfd, buffer, sizeof(buffer)); printf("Received message: %s\n", buffer); // 关闭套接字 close(sockfd); return 0; } ``` 以上的代码中,进程A创建并绑定套接字,监听连接请求,并在接受连接后,通过write函数向连接的套接字发送数据。进程B通过connect函数连接到进程A创建的套接字,并使用read函数接收进程A发送的数据。 这样,进程A和进程B就通过Uds实现了简单的进程间通讯。当然,还有其他的通讯方式,如管道、消息队列、共享内存等,在不同的场景下可以选择不同的IPC方式来进行进程间的通讯。 ### 回答3: Linux进程间通信指的是不同进程之间通过特定的机制来交换数据和信息。其中一种常见的进程间通信方式就是使用Unix套接字Unix Domain Socket,简称UDS)。 UDS是一种特殊类型的套接字,用于在同一台主机上的进程间进行通信UDS提供了一种高效的、可靠的、面向流或面向数据报的双向通信机制。 下面是一个使用UDS实现进程间通信的示例代码: ```c++ // 服务器端代码 #include <sys/socket.h> #include <sys/un.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #define SOCKET_PATH "/tmp/my_socket" int main() { int sockfd, client_sock; struct sockaddr_un server_addr, client_addr; socklen_t client_len; char buffer[256]; // 创建套接字 sockfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sockfd < 0) { perror("创建套接字失败"); exit(1); } // 绑定地址 server_addr.sun_family = AF_UNIX; strncpy(server_addr.sun_path, SOCKET_PATH, sizeof(server_addr.sun_path) - 1); unlink(SOCKET_PATH); // 确保该路径上没有残留的套接字文件 if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { perror("绑定地址失败"); exit(1); } // 监听连接 if (listen(sockfd, 5) < 0) { perror("监听连接失败"); exit(1); } // 接受客户端连接 client_len = sizeof(client_addr); client_sock = accept(sockfd, (struct sockaddr*)&client_addr, &client_len); if (client_sock < 0) { perror("接受连接失败"); exit(1); } // 读取客户端发送的消息 bzero(buffer, sizeof(buffer)); if (read(client_sock, buffer, sizeof(buffer) - 1) < 0) { perror("读取数据失败"); exit(1); } printf("接收到的消息:%s\n", buffer); // 发送响应消息给客户端 const char* response = "Hello, client!"; if (write(client_sock, response, strlen(response)) < 0) { perror("发送响应消息失败"); exit(1); } // 关闭套接字 close(client_sock); close(sockfd); return 0; } ``` ```c++ // 客户端代码 #include <sys/socket.h> #include <sys/un.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #define SOCKET_PATH "/tmp/my_socket" int main() { int sockfd; struct sockaddr_un server_addr; char buffer[256]; // 创建套接字 sockfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sockfd < 0) { perror("创建套接字失败"); exit(1); } // 连接到服务器 server_addr.sun_family = AF_UNIX; strncpy(server_addr.sun_path, SOCKET_PATH, sizeof(server_addr.sun_path) - 1); if (connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) { perror("连接服务器失败"); exit(1); } // 发送消息给服务器 const char* message = "Hello, server!"; if (write(sockfd, message, strlen(message)) < 0) { perror("发送消息失败"); exit(1); } // 读取服务器的响应消息 bzero(buffer, sizeof(buffer)); if (read(sockfd, buffer, sizeof(buffer) - 1) < 0) { perror("读取响应消息失败"); exit(1); } printf("服务器的响应消息:%s\n", buffer); // 关闭套接字 close(sockfd); return 0; } ``` 以上代码展示了一个简单的UDS通信示例,服务器端在本地创建一个套接字,并绑定地址信息,然后监听连接。客户端连接到服务器,并发送一条消息,服务器接收到消息后给客户端发送响应消息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值