天天看点

UDS(Unix Domain Socket)用在线程间通信Demo

    UDS是Linux较为常用的一种IPC方式,具体用法参考 https://blog.csdn.net/z2066411585/article/details/78966434/ 

    博主今天为验证UDS是否可用于线程之间的通信,写了一个Demo。将主线程作为服务端,子线程作为客户端,主线程向子线程传递数据(该数据存放于堆区),传递后立马在主线程中释放,再在子线程中访问(目的在于验证数据的传递是否为内容的拷贝),代码如下(testUDSacrossThreads.c):

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/stat.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<sys/un.h>
#include<errno.h>
#include<stddef.h>
#include<unistd.h>


#include <pthread.h>


const char* filename = "uds-accross-thread-test";
int fd;


void *thread_enter()
{
	int subthreadtid = pthread_self();
	printf("subthread: %u, access fd in mainthread %d\n", subthreadtid, fd);	// try to access variable in main thread? 
	/* sleep 10s here to wait for main thread */
	sleep(10);


	struct sockaddr_un un;
	int sock_fd;
	char* buf;// = (char*)malloc(sizeof(char) * 1024);
	
	un.sun_family = AF_UNIX;
	strcpy(un.sun_path, filename);
	/* create socket */
	sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
	if(sock_fd < 0)
	{
		printf("failed to create socket in subthread\n");
		exit(-1);	// how to perform?
	}
	if(connect(sock_fd, (struct sockaddr*)&un, sizeof(un)) < 0)
	{
		printf("failed to connect in subthread\n");
		exit(-1);
	}
	int ret = recv(sock_fd, buf, 1024, 0);
	if(ret < 0)
	{
		printf("failed to recv in subthread\n");
		exit(-1);
	}
	// print for 3 times with interval 5s
	for(int i = 0; i < 3; ++i)
	{
		sleep(5);
		printf("data_to_send received in subthread: %s\n", buf);
	}


	return NULL;
}


int main()
{
	int maintid = pthread_self();
	pthread_t subthread;
	char* data_to_send;


	/* create a socket */
	fd = socket(AF_UNIX, SOCK_STREAM, 0);	
	printf("main thread: create socket, fd=%d\n");
	/* create subthread */
	int rc = pthread_create(&subthread, NULL, thread_enter, NULL);
	printf("main thread: %u, create subthread: %u\n", maintid, subthread);


	/* use Unix domain socket to communicate with subthread */
	int /*fd,*/ newfd;							//	fd: use to listen, newfd: present the connection socket
	struct sockaddr_un un;					
	
	if(fd < 0)
	{
		printf("failed to create socket\n");
		exit(1);
	}
	un.sun_family = AF_UNIX;
	unlink(filename);
	strcpy(un.sun_path, filename);
	
	/* bind */
	if(bind(fd, (struct sockaddr*)&un, sizeof(un)) < 0)
	{
		printf("failed to bind\n");
		exit(1);
	}
	
	/* listen */
	if(listen(fd, 2) < 0)
	{
		printf("failed to listen\n");
		exit(1);
	}


	data_to_send = (char*)malloc(sizeof(char) * 20);
	strcpy(data_to_send, "hello world");
	int data_size = sizeof("hello world");
	printf("main thread: after strcpy data_to_send %s\n", data_to_send);
	/* accept & send data_to_send */
	do	
	{
		struct sockaddr_un subthread_addr;
		newfd = accept(fd, NULL, NULL);	//	Is this blocked? Yes, it is blocked.
		if(newfd < 0)
		{
			printf("failed to accept\n");
			exit(1);
		}
		send(newfd, data_to_send, data_size, 0);


		// free data_to_send
		free(data_to_send);
	} while(0);


	for(int i = 0; i < 30; ++i)
	{
		printf("main thread...\n");
		sleep(1);
	}
	pthread_join(subthread, NULL);
	printf("main thread: exit\n");
}
           

编译及运行:

gcc -o ./testUDSacrossThreads testUDSacrossThreads.c -pthread -std=c99

./testUDSacrossThreads

UDS(Unix Domain Socket)用在线程间通信Demo

    写这个Demo在于验证两点猜想:

    1. 从线程1(此处是main线程)通过UDS传递到线程2的数据是否通过内容的拷贝?(是)

    2. UDS是否可以用于线程间的通信?(可以)

    对于上述第一点猜想,我在子线程中直接用一个没有动态申请内存指针去接主线程过来的数据(显然这是不正确、不良好的做法),也能接住。并且主线程释放内存后,子线程中仍能访问到该数据,我想大概是内核的行为吧(没有深究)?

UDS(Unix Domain Socket)用在线程间通信Demo

    博主上学的时候没有好好学习操作系统,最近在看项目源码,涉及到 libuv 库,没有操作系统理论的支撑看得真是略痛苦,所以一边看代码,一边拓展、复习一下操作系统的理论知识。本文作为一个学习的记录过程,各路大神看完笑笑就好别吐槽小弟哈!

UDS(Unix Domain Socket)用在线程间通信Demo

继续阅读