当前位置: 首页 > news >正文

一个服务器压力测试程序

这是一个服务器压力测试程序,它本身运行在客户端,能模拟大量用户同时访问一台服务器。

#include<stdlib.h>
#include<stdio.h>
#include<assert.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/epoll.h>
#include<fcntl.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>

/* 每个客户连接不停地向服务器发送这个请求 */
static const char* request = "GET http://localhost/index.html HTTP/1.1\r\nConnection: keep-alive\r\n\r\nxxxxxxxxxxxxxxxxxxxxxxx";

int setnonblocking(int fd)
{
	int old_option = fcntl(fd, F_GETFL);
	int new_option = old_option | O_NONBLOCK;
	fcntl(fd, F_SETFL, new_option);
	return old_option;
}

void addfd(int epollfd, int fd)
{
	epoll_event event;
	event.data.fd = fd;
	event.events = EPOLLOUT | EPOLLET | EPOLLERR;
	epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event);
	setnonblocking(fd);
}

/* 向服务器写入 len 字节的数据 */
bool write_nbytes(int sockfd, const char* buffer, int len)
{
	int bytes_write = 0;
	printf("write out %d bytes to socket %d\n", len, sockfd);
	while (1)
	{
		bytes_write = send(sockfd, buffer, len, 0);
		if (bytes_write == -1)
		{
			return false;
		}
		else if (bytes_write == 0)
		{
			return false;
		}

		len -= bytes_write;
		buffer = buffer + bytes_write;
		if (len <= 0)
		{
			return true;
		}
	}
}

/* 从服务器读取数据 */
bool read_once(int sockfd, char* buffer, int len)
{
	int bytes_read = 0;
	memset(buffer, '\0', len);
	bytes_read = recv(sockfd, buffer, len, 0);
	if (bytes_read == -1)
	{
		return false;
	}
	else if (bytes_read == 0)
	{
		return false;
	}
	printf("read in %d bytes from sockfd %d with content: %s\n", bytes_read, sockfd, buffer);

	return true;
}

/* 向服务器发起 num 个 TCP 连接,我们可以通过改变 num 来调整测试压力 */
void start_conn(int epoll_fd, int num, const char* ip, int port)
{
	int ret = 0;
	struct sockaddr_in address;
	bzero(&address, sizeof(address));
	address.sin_family = AF_INET;
	address.sin_port = htons(port);
	inet_pton(AF_INET, ip, &address.sin_addr);

	for (int i = 0; i < num; ++i)
	{
		sleep(1);
		int sockfd = socket(PF_INET, SOCK_STREAM, 0);
		printf("create 1 sock\n");
		if (sockfd < 0)
		{
			continue;
		}

		if (connect(sockfd, (struct sockaddr*)&address, sizeof(address)) == 0)
		{
			printf("build connection %d\n", i);
			addfd(epoll_fd, sockfd);
		}
	}
}

void close_conn(int epollfd, int sockfd)
{
	epoll_ctl(epollfd, EPOLL_CTL_DEL, sockfd, 0);
	close(sockfd);
}

int main(int argc, char* argv[])
{
	assert(argc == 4);
	int epoll_fd = epoll_create(100);
	start_conn(epoll_fd, atoi(argv[3]), argv[1], atoi(argv[2]));
	epoll_event events[10000];
	char buffer[2048];
	while (1)
	{
		int fds = epoll_wait(epoll_fd, events, 10000, 2000);
		for (int i = 0; i < fds; ++i)
		{
			int sockfd = events[i].data.fd;
			if (events[i].events & EPOLLIN)
			{
				if (!read_once(sockfd, buffer, 2048))
				{
					close_conn(epoll_fd, sockfd);
				}
				struct epoll_event event;
				event.events = EPOLLOUT | EPOLLET | EPOLLERR;
				event.data.fd = sockfd;
				epoll_ctl(epoll_fd, EPOLL_CTL_MOD, sockfd, &event);
			}
			else if (events[i].events & EPOLLOUT)
			{
				if (!write_nbytes(sockfd, request, strlen(request)))
				{
					close_conn(epoll_fd, sockfd);
				}
				struct epoll_event event;
				event.data.fd = sockfd;
				event.events = EPOLLIN | EPOLLET | EPOLLERR;
				epoll_ctl(epoll_fd, EPOLL_CTL_MOD, sockfd, &event);
			}
			else if (events[i].events & EPOLLERR)
			{
				close_conn(epoll_fd, sockfd);
			}
		}
	}
}

相关文章:

  • 图论——二分图
  • 面向对象程序设计———组合、委托 与 继承
  • C++设计模式
  • C++ 嵌套类
  • CMake指令解析 set(CMAKE_CXX_FLAGS “$ENV{CXXFLAGS} -rdynamic -O3 -fPIC -ggdb -std=c++11 -Wall -Wno-deprec
  • 记一个测试sylar服务器日志模块时遇到的一个非常奇怪的问题
  • syscall()
  • 记一个编写宏时的错误
  • C++中全局变量,静态变量,静态局部变量 的初始化和内存分配问题
  • C++ 模板实现单例模式
  • 《C++ Primer》 异常
  • C++父类和子类指针的相互赋值和转换
  • 算法设计与分析————期末死亡冲刺
  • 现代软件工程————期末死亡冲刺
  • std::string::npos 常量解析
  • 《Java编程思想》读书笔记-对象导论
  • 【comparator, comparable】小总结
  • 08.Android之View事件问题
  • canvas绘制圆角头像
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • Docker: 容器互访的三种方式
  • iOS编译提示和导航提示
  • JavaScript HTML DOM
  • javascript面向对象之创建对象
  • Java精华积累:初学者都应该搞懂的问题
  • mysql常用命令汇总
  • mysql中InnoDB引擎中页的概念
  • vue脚手架vue-cli
  • 回顾2016
  • 基于 Babel 的 npm 包最小化设置
  • 罗辑思维在全链路压测方面的实践和工作笔记
  • 模型微调
  • 前端面试之闭包
  • 小程序测试方案初探
  • 验证码识别技术——15分钟带你突破各种复杂不定长验证码
  • 06-01 点餐小程序前台界面搭建
  • JavaScript 新语法详解:Class 的私有属性与私有方法 ...
  • kubernetes资源对象--ingress
  • ​LeetCode解法汇总2182. 构造限制重复的字符串
  • ​业务双活的数据切换思路设计(下)
  • !!Dom4j 学习笔记
  • #define、const、typedef的差别
  • #include
  • #Linux(Source Insight安装及工程建立)
  • #常见电池型号介绍 常见电池尺寸是多少【详解】
  • (6)【Python/机器学习/深度学习】Machine-Learning模型与算法应用—使用Adaboost建模及工作环境下的数据分析整理
  • (C#)Windows Shell 外壳编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令...
  • (第一天)包装对象、作用域、创建对象
  • (附源码)springboot金融新闻信息服务系统 毕业设计651450
  • (附源码)ssm教材管理系统 毕业设计 011229
  • (力扣)循环队列的实现与详解(C语言)
  • (六)激光线扫描-三维重建
  • (译)计算距离、方位和更多经纬度之间的点
  • (转)一些感悟
  • (转载)深入super,看Python如何解决钻石继承难题