用EPOLL进行压力测试

在以前的博客中提到的一个服务端,在以前压力测试的过程中,发现单核CPU最多能达到1000TPS

还以为是服务端性能不够好,所以一直想着怎么去优化它。

但优化的思路明显不多,所以就考虑换一种压力测试的方法,事实证明这个想法是对的。

 

以前的压力测试方法 :

for((i=0;i<$3;i++));do

       for((j=0;j<$4;j++));do
            cmd="./client $1 $2 4 $a $a $a $a" 
            echo `time $cmd`

       done&

done

思路是用多进程来实现并发,代码如上所示;

 

现在的压力测试方法:

//客户端程序    

/******* 客户端程序 client.c ************/    
#include  <stdio.h>   
#include  <stdlib.h>   
#include <sys/types.h>   
#include <sys/socket.h>   
#include  <string.h>   
#include  <netdb.h>   
#include <netinet/in.h>   
#include <errno.h>   
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/epoll.h>


static struct sockaddr_in server_addr;    
static int epoll_fd;
static int currency,total_req,total_read;    
static struct epoll_event* events;

int setnonblock(int fd)
{
        int flags;
        flags = fcntl(fd, F_GETFL);
        flags |= O_NONBLOCK;
        fcntl(fd, F_SETFL, flags);
}

void new_conn()
{
        if(--total_req < 0)return;
        int sockfd;
        /* 客户程序开始建立 sockfd描述符 */    
        if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)    
        {    
                fprintf(stderr,"Socket Error:%s\a\n",strerror(errno));    
                return ;
        }    
        setnonblock(sockfd);

        //让epoll接管
        struct epoll_event event;
        event.data.fd=sockfd;
        event.events = EPOLLOUT|EPOLLIN;
        epoll_ctl(epoll_fd,EPOLL_CTL_ADD, sockfd,&event);

        /* 客户程序发起连接请求 */    
        if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)    
        {    
                if(errno == EINPROGRESS)
                        return;
                fprintf(stderr,"Connect Error:%s\a\n",strerror(errno));    
                return;
        }    


}
int main(int argc, char *argv[])    
{    
        struct hostent *host;    
        if((host=gethostbyname(argv[1]))==NULL)    
        {    
                fprintf(stderr,"Gethostname error\n");    
                exit(1);    
        }    

        int portnumber;    
        if((portnumber=atoi(argv[2]))<0)    
        {    
                fprintf(stderr,"Usage:%s hostname portnumber\a\n",argv[0]);    
                exit(1);    
        }    

        /* 客户程序填充服务端的资料 */    
        bzero(&server_addr,sizeof(server_addr));    
        server_addr.sin_family=AF_INET;    
        server_addr.sin_port=htons(portnumber);    
        server_addr.sin_addr=*((struct in_addr *)host->h_addr);    

        //并发数和总的请求数
        currency = atoi(argv[3]);
        total_req = total_read = currency * atoi(argv[4]);

        if((epoll_fd=epoll_create(1000))==-1)    
        {    
                fprintf(stderr,"epoll create Error:%s\a\n",strerror(errno));    
                exit(1);    
        }    

        events = calloc(1000,sizeof(struct epoll_event));

        //初始化并发数个连接
        int i;
        for(i=0;i<currency;i++)new_conn(); 


        while(1)
        {
                fprintf(stderr,"while\n");
                int n,j;
                n = epoll_wait(epoll_fd, events, 1000, -1);
                for(j=0;j<n;j++)
                {
                        if(events[j].events & EPOLLOUT)
                        {
                                fprintf(stderr, "can write\n",n);
                                int fd = events[j].data.fd;
                                int optval;
                                socklen_t optlen = sizeof(optval);
                                if(getsockopt(fd,SOL_SOCKET,SO_ERROR,&optval, &optlen) == -1)
                                {
                                        fprintf(stderr, "getsockopt error\n",n);
                                } else if(optval != 0) {
                                        fprintf(stderr, "connect error\n",n);
                                        continue;
                                };
                                struct epoll_event event;
                                event.data.fd=fd;
                                event.events = EPOLLIN;
                                epoll_ctl(epoll_fd,EPOLL_CTL_MOD, fd,&event);

                                char buffer2[100];
                                memset(buffer2,100,0);
                                int type,score,time;
                                unsigned long oid;
                                type= htonl(atoi(argv[5]));
                                oid= htonl(atol(argv[6]));
                                score= htonl(atoi(argv[7]));
                                char*pass="220106aa";
                                char*loc = buffer2;
                                memcpy((void*)loc,(void*)(pass),8);
                                loc+=8;
                                memcpy((void*)loc,(void*)(&type),4);
                                loc+=4;
                                memcpy((void*)loc,(void*)(&oid),8);
                                loc+=8;
                                memcpy((void*)loc,(void*)(&score),4);
                                write(fd, buffer2, 24);
                                /* 连接成功了 */    
                        }
                        else if(events[j].events & EPOLLIN)
                        {
                                fprintf(stderr, "can read\n",n);
                                int fd = events[j].data.fd;
                                char buf[100];
                                int n=read(fd,buf,100);
                                close(fd);
                                new_conn();
                                if(n==-1)
                                {
                                        fprintf(stderr,"read Error:%s\a\n",strerror(errno));    
                                        continue;
                                }
                                buf[n]=0;
                                fprintf(stderr, "return %s\n",buf);
                                fprintf(stderr, "total_read %d\n",total_read);
                                if (--total_read <= 0)return;
                        }
                }
        } 
} 

思路就是用单进程来测试,用EPOOL来实现并发
代码也可下载:
百度网盘:http://pan.baidu.com/s/1vdQqB
github : https://github.com/hxdoit/real_time_rank/blob/master/server1-1.0/epoll.c

性能对比:
环境:单核CPU,两台机器,一台服务端,一台客户端
多进程:690TPS
EPOLL:6435TPS
性能提高了十倍!


分析:
在单个机器上,使用多进程,资源消耗很大,不可能达到太大的并发
而使用EPOLL,单进程同时监听多个socket,可以达到较高并发

转载于:https://www.cnblogs.com/hxdoit/p/3410199.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用 epoll 实现的服务器压力测试程序的代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/epoll.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define MAX_EVENTS 1024 #define BUFFER_SIZE 1024 void error_exit(const char *msg) { perror(msg); exit(EXIT_FAILURE); } int create_socket(const char *ip, int port) { int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { error_exit("Error creating socket"); } struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); server_addr.sin_addr.s_addr = inet_addr(ip); if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { error_exit("Error connecting to server"); } return sockfd; } int main(int argc, char *argv[]) { if (argc < 4) { printf("Usage: %s <ip> <port> <concurrency>\n", argv[0]); return 1; } const char *ip = argv[1]; const int port = atoi(argv[2]); const int concurrency = atoi(argv[3]); int epoll_fd = epoll_create1(0); if (epoll_fd < 0) { error_exit("Error creating epoll file descriptor"); } struct epoll_event ev, events[MAX_EVENTS]; char buffer[BUFFER_SIZE]; int sockets[concurrency]; int i, n, nfds; for (i = 0; i < concurrency; i++) { int sockfd = create_socket(ip, port); sockets[i] = sockfd; ev.events = EPOLLIN | EPOLLET; // Set edge-triggered mode ev.data.fd = sockfd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sockfd, &ev) < 0) { error_exit("Error adding socket to epoll"); } } while (1) { nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); if (nfds < 0) { error_exit("Error waiting for events"); } for (n = 0; n < nfds; n++) { int sockfd = events[n].data.fd; int len = read(sockfd, buffer, BUFFER_SIZE); if (len < 0) { error_exit("Error reading from socket"); } if (len == 0) { close(sockfd); ev.data.fd = sockfd; if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, sockfd, &ev) < 0) { error_exit("Error removing socket from epoll"); } int new_sockfd = create_socket(ip, port); sockets[n] = new_sockfd; ev.events = EPOLLIN | EPOLLET; // Set edge-triggered mode ev.data.fd = new_sockfd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_sockfd, &ev) < 0) { error_exit("Error adding socket to epoll"); } } } } for (i = 0; i < concurrency; i++) { close(sockets[i]); } close(epoll_fd); return 0; } ``` 该程序创建了一个 epoll 实例并向其中添加了一些套接字。它使用边缘触发模式,这意味着当套接字上有数据可读时,程序会立即收到通知。在每个套接字上读取数据时,如果读取失败或读取到的字节数为0,则关闭该套接字并创建一个新套接字,然后将其添加到 epoll 实例中。这样,程序就可以不断地创建和关闭套接字以模拟大量的并发连接。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值