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

最近碰到一个问题,两个进程间需要实时交换一些数据,数据量不是很大,就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;

}

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

时间: 2024-10-10 06:43:56

域套接字通信域共享内存通信性能比较的相关文章

信号,信号量,锁,条件变量,消息通信,共享内存,RPC (一)

在实际项目当中,经常需要把一个功能分成多个子模块实现.那么,这些子模块之间该如何关联起来呢?静态地看,模块可以看作一组完成相同功能的函数:而动态地看,模块可以是一个独立的进程.线程或者一个中断服务或者信号服务例程.根据不同的具体业务实现,它们之间可能是静态调用.动态互斥.同步.唤醒等关系.静态的调用很好实现,上层的函数调用底层的函数即可.那么,动态互斥.同步.唤醒等关系,又该如何实现呢?这就设计到我们将要讨论的信号.进程间消息通信.共享内存.线程互斥同步条件变量.RPC等手段.下面就按照Linu

父子进程共享内存通信的三种方法

1.  mmap MAP_ANONYMOUS 在支持MAP_ANONYMOUS的系统上,直接用匿名共享内存即可, 2. mmap  /dev/zero 有些系统不支持匿名内存映射,则可以使用fopen打开/dev/zero文件,然后对该文件进行映射,可以同样达到匿名内存映射的效果. 3. shmget shmat shmctl shmget 是老式的system V 共享内存模式,很多系统都支持这种方法. 父子进程共享内存通信的三种方法

如何理解“不要通过共享内存来通信,而应该通过通信来共享内存”?

不要通过共享内存来通信,而应该通过通信来共享内存 这是一句风靡golang社区的经典语,对于刚接触并发编程的人,该如何理解这句话? 如何理解"不要通过共享内存来通信,而应该通过通信来共享内存"? >> golang 这个答案描述的挺清楚的:http://www.goodpm.net/postreply/golang/1010000008937789/如何理解不要通过共享内存来通信而应该通过通信来共享内存.html

进程通信之共享内存

共享内存 共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式.不同进程之间共享的内存通常安排为同一段物理内存.进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc分配的内存一样.而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程. 共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自

linux使用共享内存通信的进程同步退出问题

两个甚至多个进程使用共享内存(shm)通信,总遇到同步问题.这里的“同步问题”不是说进程读写同步问题,这个用信号量就好了.这里的同步问题说的是同步退出问题,到底谁先退出,怎么知道对方退出了.举个例子:进程负责读写数据库A,进程B负责处理数据.那么进程A得比进程B晚退出才行,因为要保存进程B处理完的数据.可是A不知道B什么时候退出啊.A.B是无关联的进程,也不知道对方的pid.它们唯一的关联就是读写同一块共享内存.正常情况下,进程B在共享内存中写个标识:进程A你可以退出了,也是可以的.不过进程B可

linux 进程通信之 共享内存

共享内存是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容. 关于共享内存使用的API key_t ftok(const char *pathname, int proj_id); #在IPC中,我们经常用一个 key_t 的值来创建或者打开 信号量,共享内存和消息队列.这个 key_t 就是由ftok函数产生的. pathname:指定的文件名,该文件必须是存在而且可以访问 proj_

Windows环境下共享内存通信

一.引言 在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯.WIN32 API提供了许多函数使我们能够方便高效的进行进程间的通讯,通过这些函数我们可以控制不同进程间的数据交换. 进程间通讯(即:同机通讯)和数据交换有多种方式:消息.共享内存.匿名(命名)管道.邮槽.Windows套接字等多种技术."共享内存"(shared memory)可以定义为对一个以上的进程是可见的内存或存在于多个进程的虚拟地址空间.例如:如果两个进程使用相同的DLL,只把DLL的代码页装入内存

linux进程间的通信(C): 共享内存

一.共享内存介绍 共享内存是三个IPC(Inter-Process Communication)机制中的一个. 它允许两个不相关的进程访问同一个逻辑内存. 共享内存是在两个正在进行的进程之间传递数据的一种非常有效的方式. 大多数的共享内存的实现, 都把由不同进程之间共享的内存安排为同一段物理内存. 共享内存是由IPC为进程创建一个特殊的地址范围, 它将出现在该进程的地址空间中. 其他进程可以将同一段共享内存连接它们自己的地址空间中. 所有进程都可以访问共享内存中的地址, 就好像它们是由mallo

进程通信(共享内存)

共享内存: 用于进程间数据传输,是最高效的,并不提供同步,互斥  shm.h:   1 #include<stdio.h>   2 #include<stdlib.h>   3 #include<sys/ipc.h>   4 #include<sys/shm.h>   5 #include<string.h>   6 #include<sys/wait.h>   7 #include <unistd.h>   8    9