send和sendmsg性能测试

1,摘要:测试send和sendmsg的性能,影响这两个函数性能主要有发送的字节大小,增加循环次数,从100到10000000(千万)
2,基本信息
cat /proc/cpuinfo查看CPU信息,如下:

  Intel(R) Xeon(R) CPU E5-2698 v3 @ 2.30GHz

cat /proc/version 查看操作系统内核版本,如下:

  Linux version 3.10.0-327.el7.x86_64

cat /proc/meminfo查看内存信息,如下:

  MemTotal: 131748016 kB
  MemFree: 42526620 kB
  MemAvailable: 60623924 kB

3,send性能测试

服务器端 : nc -lu 8888

客服端:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include<time.h>
#include <sys/times.h>
#include <unistd.h>
//#define BUFSIZ 1024
#define recycle 1000000
static inline uint64_t rte_rdtsc(void)
{
        union {
                uint64_t tsc_64;
                struct {
                        uint32_t lo_32;
                        uint32_t hi_32;
                };
        }tsc;
        asm volatile("rdtsc":
             "=a" (tsc.lo_32),
                         "=d" (tsc.hi_32));

        return tsc.tsc_64;
}
int recycleSet[]={100,500,1000,5000,10000,50000,100000,500000,1000000,5000000,10000000};
int bufsizeSet[]={128,256,512,1024,2048,3072,4096};

int main(int argc,char *argv[])
{
        /*if(argc<3)
        {
                printf("paramaters error! ./socet_sendmsg 1000 1024");
                return -1;
        }
        int recycle_times=atoi(argv[1]);
        int buf_len=atoi(argv[2]);
    */
        int sockfd,numbytes;
    //char buf[BUFSIZ];

         int sc_clk_tck;
    sc_clk_tck = sysconf(_SC_CLK_TCK);
 sc_clk_tck = sysconf(_SC_CLK_TCK);
    struct sockaddr_in their_addr;
    //printf("break! sc_clk_tck=%d\n",sc_clk_tck);
    while((sockfd = socket(AF_INET,SOCK_DGRAM,0)) == -1);
    //printf("We get the sockfd~\n");
    their_addr.sin_family = AF_INET;
    their_addr.sin_port = htons(8888);
    their_addr.sin_addr.s_addr=inet_addr("192.168.10.8");
    bzero(&(their_addr.sin_zero), 8);


    while(connect(sockfd,(struct sockaddr*)&their_addr,sizeof(struct sockaddr)) == -1);
   // printf("Get the Server~Cheers!\n");           濉濞绔俊姣
   // numbytes = recv(sockfd, buf, BUFSIZ,0);//妤娑?
   // buf[numbytes]='\0';
   // printf("%s",buf);

        //clock_t start_time,end_time;
   // start_time=clock();
   int buf_i=0;
   for(buf_i=0;buf_i<7;buf_i++){
    int buf_len=bufsizeSet[buf_i];
    char *buf=(char *)calloc(buf_len,sizeof(char));
        int i=0;
        for(i=0;i<buf_len;i++)
        {
                buf[i]='a' + rand()%26;
        }
        buf[buf_len]='\0';
        int recycle_i=0;
        for(recycle_i=0;recycle_i<11;recycle_i++){
                int recycle_times=recycleSet[recycle_i];
        struct timeval start_time,end_time;
        gettimeofday(&start_time,NULL);
    uint64_t start=rte_rdtsc();
        for(i=0;i<recycle_times;i++)
    {

        numbytes = send(sockfd, buf, strlen(buf), 0);
            //numbytes=recv(sockfd,buf,BUFSIZ,0);
        //buf[numbytes]='\0';
       //printf("send:%d\n",numbytes);
    }
        uint64_t end=rte_rdtsc();
        //end_time=clock();
        gettimeofday(&end_time,NULL);
  uint64_t duration=end-start;
   double duration_time=1000000*(end_time.tv_sec-start_time.tv_sec)+(end_time.tv_usec-start_time.tv_usec);
   //printf("recycle_times=%d   duration=%f   numbytes=%d duration_rte=%f\n",recycle_times,duration_time,numbytes,duration/2.2);
   printf("%d,%d,%d, %f ,%f,%f\n",recycle_times,numbytes,buf_len,duration_time,duration/2.2,duration_time*1.0/recycle_times);
        }
   }
    close(sockfd);
    return 0;
}

4,sendmsg性能测试(iovlen=1)

服务器端:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
/************************************************************************************************************************

*************************************************************************************************************************/
int main(int argc, char *argv[])
{
    int fd, new_fd, struct_len, numbytes,i;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    char buff[BUFSIZ];
	//struct msghdr msg;  
	bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8888);
    server_addr.sin_addr.s_addr = INADDR_ANY;
   // bzero(&(server_addr.sin_zero), 8);
    struct_len = sizeof(struct sockaddr_in);
   while((fd = socket(AF_INET,SOCK_DGRAM,0)) == -1);
   if (bind(fd, (struct sockaddr*)(&server_addr), struct_len) < 0)  
   {  
      fprintf(stderr, "bind fail\n");  
      exit(EXIT_FAILURE);  
   }  
   printf("Bind Success!\n");
   // fd = socket(AF_INET, SOCK_DGRAM, 0);
    /*while(bind(fd, (struct sockaddr *)&server_addr, struct_len) == -1);
    printf("Bind Success!\n");
    while(listen(fd, 100) == -1);
    printf("Listening....\n");
    printf("Ready for Accept,Waitting...\n");
    new_fd = accept(fd, (struct sockaddr *)&client_addr, &struct_len);
    */
	//printf("Get the Client.\n");
   // numbytes = send(new_fd,"Welcome to my server\n",21,0); 
    while(1)
    {
		printf("recemsg\n");
		struct msghdr msg; 
		bzero(&msg,sizeof(struct msghdr));
		msg.msg_name =&client_addr;  
        msg.msg_namelen =sizeof(struct sockaddr_in);  
		struct iovec io;
        io.iov_base =buff;  
        io.iov_len =BUFSIZ;
		 msg.msg_iov = &io;  
		msg.msg_iovlen = 1; 
		numbytes = recvmsg(fd,&msg,0);
         char * temp = msg.msg_iov[0].iov_base;//获取得到的数据
        temp[numbytes] = '\0';//为数据末尾添加结束符
       // printf("get %d message:%s", numbytes,temp);
		printf("get %d \n", numbytes);
    }
   // close(new_fd);
    close(fd);
    return 0;
}

  客服端:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include<time.h>
#include <sys/times.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
//#define BUFSIZ 1024
#define recycle 1000000 
static inline uint64_t rte_rdtsc(void)
{
	union {
		uint64_t tsc_64;
		struct {
			uint32_t lo_32;
			uint32_t hi_32;
		};
	}tsc;
	asm volatile("rdtsc":
             "=a" (tsc.lo_32),
			 "=d" (tsc.hi_32));
			 
	return tsc.tsc_64;
}
int recycleSet[]={100,500,1000,5000,10000,50000,100000,500000,1000000,5000000,10000000};
int bufsizeSet[]={128,256,512,1024,2048,3072,4096};

int main(int argc,char *argv[])
{
	/*if(argc<3)
	{
		printf("paramaters error! ./socet_sendmsg 1000 1024");
		return -1;
	}
	int recycle_times=atoi(argv[1]);
	int buf_len=atoi(argv[2]);
    */
	int sockfd,numbytes;
    //char buf[BUFSIZ];
	
	 int sc_clk_tck;
    sc_clk_tck = sysconf(_SC_CLK_TCK);
    struct sockaddr_in their_addr;
    //printf("break! sc_clk_tck=%d\n",sc_clk_tck);
    while((sockfd = socket(AF_INET,SOCK_DGRAM,0)) == -1);
    //printf("We get the sockfd~\n");
	bzero(&their_addr, sizeof(their_addr));
    their_addr.sin_family = AF_INET;
    their_addr.sin_port = htons(8888);
    their_addr.sin_addr.s_addr=inet_addr("192.168.10.8");
	//their_addr.sin_addr.s_addr=htonl(INADDR_ANY);
    //bzero(&(their_addr.sin_zero), 8);
    
		
   // while(connect(sockfd,(struct sockaddr*)&their_addr,sizeof(struct sockaddr)) == -1);
   // printf("Get the Server~Cheers!\n");
   // numbytes = recv(sockfd, buf, BUFSIZ,0);//接收服务器端信息  
   // buf[numbytes]='\0';  
   // printf("%s",buf);
	
	//clock_t start_time,end_time;
   // start_time=clock();
   int buf_i=0;
   for(buf_i=0;buf_i<7;buf_i++){
    int buf_len=bufsizeSet[buf_i];
    char *buf=(char *)calloc(buf_len,sizeof(char));
	int i=0;
	for(i=0;i<buf_len;i++)
	{
		buf[i]='a' + rand()%26;
	}
	buf[buf_len]='\0';
	struct msghdr msg;
	bzero(&msg,sizeof(struct msghdr));
	//msg.msg_name = NULL;
	msg.msg_name = &their_addr;  
    msg.msg_namelen = sizeof(struct sockaddr_in);
	struct iovec io;
	io.iov_base = buf;
	io.iov_len = buf_len;
	msg.msg_iov = &io;
	msg.msg_iovlen = 1;	 
	int recycle_i=0;
	for(recycle_i=0;recycle_i<11;recycle_i++){
		int recycle_times=recycleSet[recycle_i];
	struct timeval start_time,end_time;
	gettimeofday(&start_time,NULL);
    uint64_t start=rte_rdtsc();
	for(i=0;i<recycle_times;i++)
    {
       
        //numbytes = send(sockfd, buf, strlen(buf), 0);
		numbytes = sendmsg(sockfd, &msg, 0);
            //numbytes=recv(sockfd,buf,BUFSIZ,0);  
        //buf[numbytes]='\0'; 
       //printf("send:%d\n",numbytes);  
    }
	uint64_t end=rte_rdtsc();
	//end_time=clock();
	gettimeofday(&end_time,NULL);
	uint64_t duration=end-start;
   double duration_time=1000000*(end_time.tv_sec-start_time.tv_sec)+(end_time.tv_usec-start_time.tv_usec);
   //printf("recycle_times=%d   duration=%f   numbytes=%d duration_rte=%f\n",recycle_times,duration_time,numbytes,duration/2.2);
   printf("%d,%d,%d, %f ,%f,%f\n",recycle_times,numbytes,buf_len,duration_time,duration/2.2,duration_time*1.0/recycle_times);
	}
   }
    close(sockfd);
    return 0;
}

4,sendmsg性能测试(iovlen=4)

服务器端:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include<time.h>
#include <sys/times.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
//#define BUFSIZ 1024
#define recycle 1000000 
static inline uint64_t rte_rdtsc(void)
{
	union {
		uint64_t tsc_64;
		struct {
			uint32_t lo_32;
			uint32_t hi_32;
		};
	}tsc;
	asm volatile("rdtsc":
             "=a" (tsc.lo_32),
			 "=d" (tsc.hi_32));
			 
	return tsc.tsc_64;
}
int recycleSet[]={100,500,1000,5000,10000,50000,100000,500000,1000000,5000000,10000000};
int bufsizeSet[]={128,256,512,1024,2048,3072,4096,5120,6144,7168,8192,9216,15000,150000};
#define BUF_CNT 14
int main(int argc,char *argv[])
{
	/*if(argc<3)
	{
		printf("paramaters error! ./socet_sendmsg 1000 1024");
		return -1;
	}
	int recycle_times=atoi(argv[1]);
	int buf_len=atoi(argv[2]);
    */
	int sockfd,numbytes;
    //char buf[BUFSIZ];
	
	 int sc_clk_tck;
    sc_clk_tck = sysconf(_SC_CLK_TCK);
    struct sockaddr_in their_addr;
    //printf("break! sc_clk_tck=%d\n",sc_clk_tck);
    while((sockfd = socket(AF_INET,SOCK_DGRAM,0)) == -1);
    //printf("We get the sockfd~\n");
	bzero(&their_addr, sizeof(their_addr));
    their_addr.sin_family = AF_INET;
    their_addr.sin_port = htons(9999);
    their_addr.sin_addr.s_addr=inet_addr("192.168.10.8");
	//their_addr.sin_addr.s_addr=htonl(INADDR_ANY);
    //bzero(&(their_addr.sin_zero), 8);
    
		
   // while(connect(sockfd,(struct sockaddr*)&their_addr,sizeof(struct sockaddr)) == -1);
   // printf("Get the Server~Cheers!\n");
   // numbytes = recv(sockfd, buf, BUFSIZ,0);//接收服务器端信息  
   // buf[numbytes]='\0';  
   // printf("%s",buf);
	
	//clock_t start_time,end_time;
   // start_time=clock();
   int buf_i=0;
   for(buf_i=0;buf_i<14;buf_i++){
    int buf_len=bufsizeSet[buf_i];
    char *buf=(char *)calloc(buf_len,sizeof(char));
	int i=0;
	for(i=0;i<buf_len;i++)
	{
		buf[i]='a' + rand()%26;
	}
	buf[buf_len]='\0';
	struct msghdr msg;
	bzero(&msg,sizeof(struct msghdr));
	//msg.msg_name = NULL;
	msg.msg_name = &their_addr;  
    msg.msg_namelen = sizeof(struct sockaddr_in);
	struct iovec io[4];
	io[0].iov_base = buf;
	io[0].iov_len = buf_len;
	io[1].iov_base = buf;
	io[1].iov_len = buf_len;
	io[2].iov_base = buf;
	io[2].iov_len = buf_len;
	io[3].iov_base = buf;
	io[3].iov_len = buf_len;
	
	msg.msg_iov = io;
	msg.msg_iovlen =4;	 
	int recycle_i=0;
	for(recycle_i=8;recycle_i<9;recycle_i++){
		int recycle_times=recycleSet[recycle_i];
	struct timeval start_time,end_time;
	gettimeofday(&start_time,NULL);
    uint64_t start=rte_rdtsc();
	for(i=0;i<recycle_times;i++)
    {
       
        //numbytes = send(sockfd, buf, strlen(buf), 0);MSG_DONTWAIT
		numbytes = sendmsg(sockfd, &msg, 0);
            //numbytes=recv(sockfd,buf,BUFSIZ,0);  
        //buf[numbytes]='\0'; 
       //printf("send:%d\n",numbytes);  
    }
	uint64_t end=rte_rdtsc();
	//end_time=clock();
	gettimeofday(&end_time,NULL);
	uint64_t duration=end-start;
   double duration_time=1000000*(end_time.tv_sec-start_time.tv_sec)+(end_time.tv_usec-start_time.tv_usec);
   //printf("recycle_times=%d   duration=%f   numbytes=%d duration_rte=%f\n",recycle_times,duration_time,numbytes,duration/2.2);
   printf("%d,%d,%d, %f ,%f,%f\n",recycle_times,numbytes,buf_len,duration_time,duration/2.3,duration_time*1.0/recycle_times);
	}
   }
    close(sockfd);
    return 0;
}

  客户端:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
/************************************************************************************************************************
1、int socket(int family,int type,int protocol)
family:
    指定使用的协议簇:AF_INET(IPv4) AF_INET6(IPv6) AF_LOCAL(UNIX协议) AF_ROUTE(路由套接字) AF_KEY(秘钥套接字)
type:
    指定使用的套接字的类型:SOCK_STREAM(字节流套接字) SOCK_DGRAM
protocol:
    如果套接字类型不是原始套接字,那么这个参数就为0
2、int bind(int sockfd, struct sockaddr *myaddr, int addrlen)
sockfd:
    socket函数返回的套接字描述符
myaddr:
    是指向本地IP地址的结构体指针
myaddrlen:
    结构长度
struct sockaddr{
    unsigned short sa_family; //通信协议类型族AF_xx
    char sa_data[14];  //14字节协议地址,包含该socket的IP地址和端口号
};
struct sockaddr_in{
    short int sin_family; //通信协议类型族
    unsigned short int sin_port; //端口号
    struct in_addr sin_addr; //IP地址
    unsigned char si_zero[8];  //填充0以保持与sockaddr结构的长度相同
};
3、int connect(int sockfd,const struct sockaddr *serv_addr,socklen_t addrlen)
sockfd:
    socket函数返回套接字描述符
serv_addr:
    服务器IP地址结构指针
addrlen:
    结构体指针的长度
4、int listen(int sockfd, int backlog)
sockfd:
    socket函数绑定bind后套接字描述符
backlog:
    设置可连接客户端的最大连接个数,当有多个客户端向服务器请求时,收到此值的影响。默认值20
5、int accept(int sockfd,struct sockaddr *cliaddr,socklen_t *addrlen)
sockfd:
    socket函数经过listen后套接字描述符
cliaddr:
    客户端套接字接口地址结构
addrlen:
    客户端地址结构长度
6、int send(int sockfd, const void *msg,int len,int flags)
7、int recv(int sockfd, void *buf,int len,unsigned int flags)
sockfd:
    socket函数的套接字描述符
msg:
    发送数据的指针
buf:
    存放接收数据的缓冲区
len:
    数据的长度,把flags设置为0
*************************************************************************************************************************/
int main(int argc, char *argv[])
{
    int fd, new_fd, struct_len, numbytes,i;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    char buff[BUFSIZ*10];
	printf("BUFFSIZE %d\n",BUFSIZ);
	//struct msghdr msg;  
	bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(9999);
    server_addr.sin_addr.s_addr = INADDR_ANY;
   // bzero(&(server_addr.sin_zero), 8);
    struct_len = sizeof(struct sockaddr_in);
   while((fd = socket(AF_INET,SOCK_DGRAM,0)) == -1);
   if (bind(fd, (struct sockaddr*)(&server_addr), struct_len) < 0)  
   {  
		printf("bind error\n");
		return -1;
   }
   printf("Bind Success!\n");
   // fd = socket(AF_INET, SOCK_DGRAM, 0);
    /*while(bind(fd, (struct sockaddr *)&server_addr, struct_len) == -1);
    printf("Bind Success!\n");
    while(listen(fd, 100) == -1);
    printf("Listening....\n");
    printf("Ready for Accept,Waitting...\n");
    new_fd = accept(fd, (struct sockaddr *)&client_addr, &struct_len);
    */
	//printf("Get the Client.\n");
   // numbytes = send(new_fd,"Welcome to my server\n",21,0); 
   int cnt=0;
    while(1)
    {
		printf("recemsg\n");
		struct msghdr msg; 
		bzero(&msg,sizeof(struct msghdr));
		msg.msg_name =&client_addr;  
        msg.msg_namelen =sizeof(struct sockaddr_in);  
		struct iovec io;
        io.iov_base =buff;  
        io.iov_len =BUFSIZ*100;
		 msg.msg_iov = &io;  
		msg.msg_iovlen = 5; 
		numbytes = recvmsg(fd,&msg,0);
         char * temp = msg.msg_iov[0].iov_base;//获取得到的数据
        temp[numbytes] = '\0';//为数据末尾添加结束符
       // printf("get %d message:%s", numbytes,temp);
	   if(numbytes>0)
		   cnt++;
		printf("get %d  cnt %d\n", numbytes,cnt);
    }
   // close(new_fd);
    close(fd);
    return 0;
}

  

 

6,send测试数据表

 

7,sendmsg测试数据表(iovlen=1)

 7,sendmsg测试数据表(iovlen=4)

8,比较send,sendmsg(iovlen=1),sendmsg(iovlen=4)

 9,用gettimeofday测试性能基本逻辑(gettimeofday和滴答数转化成时间基本差不多)

单位为:微秒

struct timeval start_time,end_time;
gettimeofday(&start_time,NULL);
uint64_t start=rte_rdtsc();

函数调用

uint64_t end=rte_rdtsc();
//end_time=clock();
gettimeofday(&end_time,NULL);
uint64_t duration=end-start;
double duration_time=1000000*(end_time.tv_sec-start_time.tv_sec)+(end_time.tv_usec-start_time.tv_usec);

8,send和sendmsg性能测试比较(循环一千万次,算出一次时间开销(微秒))

结论:

1,send和sendmsg的性能基本一样

2,性能随字节成正比,比如128B~1.55微秒 ,256B~2.57微秒,1024B~8.72微秒,4096B~34.22微秒

3,sendmsg(iovlen=1)和sendmsg(iovlen=4)的在发送相同字节情况下,性能也是4倍,sendmsg在性能上并没得到优化

 

posted on 2018-05-23 22:05  woshare  阅读(3364)  评论(0编辑  收藏  举报