1. 程式人生 > >域套接字通訊域共享記憶體通訊效能比較

域套接字通訊域共享記憶體通訊效能比較

最近碰到一個問題,兩個程序間需要實時交換一些資料,資料量不是很大,就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;

}


相關推薦

通訊共享記憶體通訊效能比較

最近碰到一個問題,兩個程序間需要實時交換一些資料,資料量不是很大,就72個位元組。當時估計簡單起見,用的是域套接字的方式。 後續效能測試的時候,忽然發現當網路包併發量很大時,效能忽然大幅下降,用strace跟蹤發現,忽然有好多的read,write操作,檢視程式碼跟蹤到此處

嵌入式linux網路程式設計,UNIX,AF_LOCAL,PF_LOCAL,PF_UNIX,,AF_UNIX,程序間通訊機制

文章目錄 1,UNIX域套接字 2,UNIX域套接字模型 3,UNIX域套接字 --- 示例 3.1,net.h 3.2,client.c 3.3,sever.c 3.4,linklist.h 3.5,link

程序筆記2:程序之間的通訊(UNIXsocket)

socket的地址資料結構根據不同的系統以及網路環境有不同形式。為了使不同格式地址能夠被傳入套接字函式,必須強制將地址結構轉換為: struct sockaddr{ sa_family_t sa_family; /* address family*/ char

使用Unix進行跨程序通訊

Unix域套接字簡介 《Unix環境高階程式設計》中對Unix域套接字有如下介紹: 雖然socketpair函式建立相互連線的一對套接字,但是每一個套接字都沒有名字。這意味著無關程序不能使用它們。 我們可以命名unix域套接字,並可將其用於告示服務。但是要

go語言unix發送udp報文

dial ring pack sock world lis add client 語言 /* server.go */package mainimport ( "fmt" "net" &quo

【Nebula系列】通過UNIX傳遞描述符的應用

_file__ 直接 sca linux網絡 tran 和數 權限 cif .cpp ??傳送文件描述符是高並發網絡服務編程的一種常見實現方式。Nebula 高性能通用網絡框架即采用了UNIX域套接字傳遞文件描述符設計和實現。本文詳細說明一下傳送文件描述符的應用。 1. T

通過UNIX傳遞文件描述符

and starting github option nts wiki 靜態方法 socket union 傳送文件描述符是高並發網絡服務編程的一種常見實現方式。Nebula 高性能通用網絡框架即采用了UNIX域套接字傳遞文件描述符設計和實現。本文詳細說明一下傳送文件描述符

20-unix地址結構

1. unix域協議 看到這個標題,不知道的小夥伴肯定以為這是一個協議族之類的,但實際上unix域協議是在單臺主機上客戶端與服務端之間的通訊方法,簡單來說,unix域協議也是一種程序間通訊方式,用於同一臺主機上的客戶端和服務端,為不同的程序間傳遞描述符。 通常在同一臺主機上,使用unix

UNIX中的抽象名字空間

原文地址:http://blog.chinaunix.net/uid-317451-id-92602.html UNIX域(PF_UNIX、PF_LOCAL或AF_UNIX、AF_LOCAL)套接字為UNIX系統的本地程序間的雙向資料通訊提供了高效的解決方案。 我們可以認為

linux網路程式設計之socket(十六):通過UNIX傳遞描述符和 sendmsg/recvmsg 函式

void send_fd(int sock_fd, int send_fd) {     int ret;     struct msghdr msg;     struct cmsghdr *p_cmsg;     struct iovec vec;     char cmsgbuf[CMSG_SPACE(

Java 網路程式設計(五) 使用TCP/IP的(Socket)進行通訊

使用TCP/IP的套接字(Socket)進行通訊 套接字Socket的引入   為了能夠方便地開發網路應用軟體,由美國伯克利大學在Unix上推出了一種應用程式訪問通訊協議的作業系統用呼叫socket(套接字)。   socket的出現,使程式設計師可以很方便地訪問TCP/

多程序程式設計之程序間通訊-共享記憶體,訊號量和

1. 背景 本文將介紹程序通訊中的訊號量,共享記憶體和套接字方法。 2. 訊號量 2.1 訊號量的定義 為了防止出現因多個程式同時訪問一個共享資源而引發的一系列問題,我們需要一種方法,它可以通過生成並使用令牌來授權,在任一時刻只能有一個執行執行緒

人工智慧(PythonNet)—— 程序間通訊(管道、訊息佇列、共享記憶體、訊號、訊號量、

一、程序間通訊        程序間通訊(IPC,InterProcess Communication)是指在不同程序之間傳播或交換資訊。        由於每個程序的空間是互相獨立的,程序之間無法互相直接獲取彼此的資源,故引入程序間通訊來實現程序間的資源互動。       

程序間通訊(IPC)-管道、訊息佇列、共享記憶體、訊號、訊號量、

多程序:首先,先來講一下fork之後,發生了什麼事情。由fork建立的新程序被稱為子程序(child process)。該函式被呼叫一次,但返回兩次。兩次返回的區別是子程序的返回值是0,而父程序的返回值則是新程序(子程序)的程序 id。將子程序id返回給父程序的理由是:因為一

Linux下程序間通訊方式之管道、訊號、共享記憶體、訊息佇列、訊號量、

/* 1,程序間通訊 (IPC ) Inter-Process Communication   比較好理解概念的就是程序間通訊就是在不同程序之間傳播或交換資訊。 2,linux下IPC機制的分類:管道、訊號、共享記憶體、訊息佇列、訊號量、套接字 3,這篇主要說說管

Python之路(第三十一篇) 網路程式設計:簡單的tcp通訊、粘包現象

  一、簡單的tcp套接字通訊 套接字通訊的一般流程 服務端 server = socket() #建立伺服器套接字 server.bind() #把地址繫結到套接字,網路地址加埠 server.listen() #監聽連結 inf_loop:

簡單的通訊\加通訊迴圈\修復bug\連結迴圈

客戶端 import socket # 1、買手機 phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 2、打電話 phone.connect(("127.0.0.1", 8080)) # phone相當於服務端的conn #

Visual C++網路程式設計經典案例詳解 第3章 多執行緒與非同步程式設計 程序間通訊 命名管道 命名管道例項

vc新增控制檯工程 名字命名管道例項 新增原始檔 名字 伺服器 #include<windows.h>                                //包含標頭檔案 #include<stdio.h> int main() {  

流式C/S通訊程式

客戶端 #include"stdafx.h" #define WIN32_LEAN_AND_MEAN #include<Windows.h> #include<WinSock2.h> #include<WS2tcpip.h>

linux網路通訊-

socket程式設計是網路常用的程式設計,我們通過在網路中建立socket關鍵字來實現網路間的通訊。 1.TCP/IP協議 先來簡單瞭解一下TCP/IP協議: iso7層架構 應用層 應用層不僅要提供應用程序所需要資訊交換和遠端操作,而且還要作為應用程序