版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/timebomb/article/details/38417547
最近碰到一个问题,两个进程间需要实时交换一些数据,数据量不是很大,就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;
}