首页 > 代码库 > 域套接字通信域共享内存通信性能比较

域套接字通信域共享内存通信性能比较

最近碰到一个问题,两个进程间需要实时交换一些数据,数据量不是很大,就72个字节。当时估计简单起见,用的是域套接字的方式。

后续性能测试的时候,忽然发现当网络包并发量很大时,性能忽然大幅下降,用strace跟踪发现,忽然有好多的read,write操作,查看代码跟踪到此处,发现是域套接字需要不断的读写操作,虽然保证了数据的安全按序到达,但是此种操作性能太低。自己就想,两者究竟相差多少呢?跑两个程序比较下,一目了然。代码有些是用的网上现成的,水平有限,勿喷。


结果写在前面防止你看不到:域套接字跟共享内存完全不在一个数量级,域套接字是步行的话,共享内存跟跑车差不多。

详细时间值大概相差30多倍(使用perf stat测试)。


1、域套接字客户端:

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/un.h>
#include <errno.h>
#include <string.h>
#define DIS_MSG_FILE "/tmp/.dis_msg"
typedef struct _key_args
{
	unsigned int key;
	union {	
		u_int32_t ipv4_addr;
		u_int32_t ipv6_addr[4];
	} sip;	
	union {	
		u_int32_t ipv4_addr;
		u_int32_t ipv6_addr[4];	
	} dip;
	unsigned short sport;
	unsigned short dport;
	unsigned char protocol;
	unsigned short match_type;
	unsigned short iptype;
	//unsigned short mask;
	int core_id;
}key_args_t;

typedef struct _dis_msg_buff
{
	long mtype;
	unsigned int key;
	int core_num;
	int msg_type;
	key_args_t karg;
}dis_msg_buff_t;

int main()
{
	int i = 0;
	int fd = 0;
	int len = 0;
	int ret = 0;
	char reerrno = 0;
	struct sockaddr_un addr;
	dis_msg_buff_t msg;
	time_t t;
	t = time(NULL);

	fd = socket(AF_UNIX, SOCK_STREAM, 0);
	if (fd < 0){
		printf("CLIENT: socket error\n");
		return -1;
	}

	memset(&addr, 0x00, sizeof(struct sockaddr_un));
	addr.sun_family = AF_UNIX;
	strncpy(addr.sun_path, DIS_MSG_FILE,strlen(DIS_MSG_FILE));

	len = sizeof(addr.sun_family);
#ifdef HAVE_SUN_LEN
	len = addr.sun_len = SUN_LEN(&addr);
#else
	len = sizeof (addr.sun_family) + strlen (addr.sun_path);
#endif /* HAVE_SUN_LEN */
	ret = connect(fd, (struct sockaddr *)&addr, len);
	if (ret<0){
		printf("CLIENT: connect error\n");
		return -1;
	}
	
/*------------------------通信100w次---------------------------*/
	while(i++ < 1000000){
		memset(&msg, 0x00, sizeof(msg));
		if(write(fd, &msg, sizeof(msg)) < 0)
		{
			printf("CLIENT: write error\n");
			goto err;
		}
		while(1){
			int nbytes;
			reerrno = 0;
			nbytes = read(fd, &reerrno, sizeof(reerrno));
			if (nbytes <= 0 && errno != EINTR)
				goto err;
			if (nbytes > 0){
				if (reerrno == 1)
					break;
				else
					goto err;
			}
		}
	}
/*------------------------通信100w次-结束--------------------------*/
	close(fd);
	printf("CLIENT: success  %d\n", time(NULL)-t);
	return 0;
err:
	close(fd);
	printf("CLIENT: failed\n");
	return -1;
}


2、域套接字服务器:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <unistd.h>
#include <termios.h>
#include <sys/stat.h>
/**********定时器头文件***************/
#include <sys/time.h>
#include <signal.h>
/***********进程间SOCKET通信头文件**********/
#include <sys/socket.h>
#include <sys/un.h>

#define UNIX_DOMAIN "/tmp/.dis_msg"
typedef struct _key_args
{
	unsigned int key;
	union {	
		u_int32_t ipv4_addr;
		u_int32_t ipv6_addr[4];
	} sip;	
	union {	
		u_int32_t ipv4_addr;
		u_int32_t ipv6_addr[4];	
	} dip;
	unsigned short sport;
	unsigned short dport;
	unsigned char protocol;
	unsigned short match_type;
	unsigned short iptype;
	//unsigned short mask;
	int core_id;
}key_args_t;
typedef struct _dis_msg_buff
{
	long mtype;
	unsigned int key;
	int core_num;
	int msg_type;
	key_args_t karg;
}dis_msg_buff_t;

void main()
{
	socklen_t clt_addr_len;
	int listen_fd;
	int com_fd;
	int ret=0;
	char reerrno = 0;
	int i;
	dis_msg_buff_t msg;

	int len;
	struct sockaddr_un clt_addr;
	struct sockaddr_un srv_addr;
	//创建用于通信的套接字,通信域为UNIX通信域
	listen_fd=socket(AF_UNIX,SOCK_STREAM,0);
	if(listen_fd<0)
	{
		printf("SERVER:cannot create listening socket\n");
		return;
	}
	//设置服务器地址参数
	srv_addr.sun_family=AF_UNIX;
	strncpy(srv_addr.sun_path,UNIX_DOMAIN,sizeof(srv_addr.sun_path)-1);
	unlink(UNIX_DOMAIN);
	//绑定套接字与服务器地址信息
	ret=bind(listen_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
	if(ret==-1)
	{
		printf("cannot bind server socket\n");
		close(listen_fd);
		unlink(UNIX_DOMAIN);
		return;
	}
	//对套接字进行监听,判断是否有连接请求
	ret=listen(listen_fd,1);
	if(ret==-1)
	{
		printf("cannot listen the client connect request\n");
		close(listen_fd);
		unlink(UNIX_DOMAIN);
		return;
	}
	chmod(UNIX_DOMAIN,00777);//设置通信文件权限
	//当有连接请求时,调用accept函数建立服务器与客户机之间的连接
	len=sizeof(clt_addr);
	com_fd=accept(listen_fd,(struct sockaddr*)&clt_addr,&len);
	if(com_fd<0)
	{
		printf("cannot accept client connect request");
		close(listen_fd);
		unlink(UNIX_DOMAIN);
		return;
	}
/*------------------------通信100w次---------------------------*/	
	while(1){
		//读取并输出客户端发送过来的连接信息
		memset(&msg,0x00,sizeof(msg));
		int recv_php_num=read(com_fd,&msg,sizeof(msg));
		if (recv_php_num <= 0){
			printf("read error\n");
			return;
		}
		reerrno = 1;
		write(com_fd,&reerrno,sizeof(reerrno));
		reerrno = 0;
	}
}


3、共享内存客户端:

#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <errno.h>
#include <string.h>
#include <time.h>

#define MY_SHM_ID 815

struct shared_use_at{
	int written_by_you;
	char some_text[72];
};

int main()
{
	int shmid, ret;
    time_t t;
    t = time(NULL);
	
	shmid = shmget(MY_SHM_ID, sizeof(struct shared_use_at), 0666);
	if(shmid > 0)
		printf("Create a shared memory segment %d\n", shmid);
	else if(shmid == EEXIST){
		printf("shared memory is exist!\n");
		exit(0);
	}
	printf("shmid = %d, EEXIST = %d\n", shmid, EEXIST);
	struct shmid_ds shmds;
	ret = shmctl(shmid, IPC_STAT, &shmds);
	if(ret == 0){
		printf("Size of memory segment is %d\n", (int)shmds.shm_segsz);
		printf("Number of attches %d\n", (int)shmds.shm_nattch);
	}else{
		printf("shmctl() call failed\n");
	}

	int running = 1;
	char buffer[100] = {0};
	void *shared_memory = (void *)0;
	struct shared_use_at *shared_stuff;
	shared_memory = shmat(shmid, (void *)0, 0);
	if(shared_memory == (void*)-1){
		printf("shmat failed\n");
		exit(0);
	}
	shared_stuff = (struct shared_use_at *)shared_memory;
	
/*------------------------通信100w次---------------------------*/
	while(running++<1000000){
		while(shared_stuff->written_by_you == 1){
		}
		memset(shared_stuff->some_text, 0x00, 72);
        shared_stuff->some_text[0] = 'o';
		shared_stuff->written_by_you = 1;
	}
/*------------------------通信100w次--结束-----------------------*/

    printf("time = %d\n", (int)(time(NULL) - t));
    shared_stuff->some_text[0] = 'k';
	shared_stuff->written_by_you = 1;
	ret = shmdt(shared_memory);
	if(ret == 0)
		printf("shmdt memory \n");
	else 
		printf("shmdt memory failed \n");

	ret = shmctl(shmid, IPC_RMID, 0);
	if(ret == 0)
		printf("shared memory removed \n");
	else
		printf("shared memory removed failed\n");
	return 0;

}


4、共享内存服务器:

#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <errno.h>

#define MY_SHM_ID 815

struct shared_use_at{
	int written_by_you;
	char some_text[72];
};

int main()
{
	printf("page size = %d\n", getpagesize());
	int shmid, ret;
	shmid = shmget(MY_SHM_ID, sizeof(struct shared_use_at), 0666|IPC_CREAT);
	if(shmid > 0)
		printf("Create a shared memory segment %d\n", shmid);
	struct shmid_ds shmds;
	ret = shmctl(shmid, IPC_STAT, &shmds);
	if(ret == 0){
		printf("Size of memory segment is %d\n", (int)shmds.shm_segsz);
		printf("Number of attches %d\n", (int)shmds.shm_nattch);
	}else{
		printf("shmctl() call failed\n");
	}

	int running = 1;
    int arunning = 1;
	void *shared_memory = (void *)0;
	struct shared_use_at *shared_stuff;
	shared_memory = shmat(shmid, (void *)0, 0);
	if(shared_memory == (void*)-1){
		printf("shmat failed\n");
		exit(0);
	}
	shared_stuff = (struct shared_use_at *)shared_memory;
	shared_stuff->written_by_you = 0;

/*------------------------通信100w次---------------------------*/
	while(running++){
		if(shared_stuff->written_by_you){
			if(shared_stuff->some_text[0] == 'o')
                arunning++;
            if(shared_stuff->some_text[0] == 'k')
                break;
		    shared_stuff->written_by_you = 0;
		}
	}
/*------------------------通信100w次--结束-------------------------*/
    printf("arunning = %d, running = %d \n", arunning, running);
	ret = shmdt(shared_memory);
	if(ret == 0)
		printf("shmdt memory \n");
	else 
		printf("shmdt memory failed \n");

	ret = shmctl(shmid, IPC_RMID, 0);
	if(ret == 0)
		printf("shared memory removed \n");
	else
		printf("shared memory removed failed\n");
	return 0;

}