C++实现web服务器,然后压力测试,最后通过函数进行指标值的获取,并且打印输出 代码或者函数
时间: 2024-05-16 20:14:38 浏览: 113
以下是一个简单的用 C 语言实现的 web 服务器,同时提供了压力测试和指标值获取的功能:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <time.h>
#define PORT 8080
#define MAX_REQUEST_SIZE 2048
#define MAX_RESPONSE_SIZE 4096
#define MAX_CLIENTS 100
int server_fd, client_sockets[MAX_CLIENTS], max_clients = MAX_CLIENTS;
fd_set read_fds;
char *response_template = "HTTP/1.1 200 OK\nContent-Type: text/html\n\n<html><body><h1>Hello, World!</h1></body></html>\n";
int response_size = 0;
int init_server();
int accept_connections();
int handle_request(int client_socket);
int send_response(int client_socket);
void close_server();
int get_random_number(int min, int max);
int main() {
int i, activity, client_socket, sd, max_sd;
int request_count = 0, response_count = 0;
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
// 初始化服务器
if (init_server() < 0) {
return 1;
}
// 初始化响应消息体
response_size = strlen(response_template);
// 随机产生一些请求
srand(time(NULL));
for (i = 0; i < 1000; i++) {
int client_socket = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
connect(client_socket, (struct sockaddr *)&server_addr, sizeof(server_addr));
send(client_socket, "GET / HTTP/1.1\r\n\r\n", strlen("GET / HTTP/1.1\r\n\r\n"), 0);
close(client_socket);
}
while (1) {
// 初始化文件描述符集合
FD_ZERO(&read_fds);
FD_SET(server_fd, &read_fds);
max_sd = server_fd;
for (i = 0; i < max_clients; i++) {
client_socket = client_sockets[i];
if (client_socket > 0) {
FD_SET(client_socket, &read_fds);
}
if (client_socket > max_sd) {
max_sd = client_socket;
}
}
// 等待文件描述符集合中的文件可读
activity = select(max_sd + 1, &read_fds, NULL, NULL, &tv);
if ((activity < 0) && (errno != EINTR)) {
printf("select error\n");
break;
}
// 处理新连接
if (FD_ISSET(server_fd, &read_fds)) {
accept_connections();
}
// 处理客户端请求
for (i = 0; i < max_clients; i++) {
sd = client_sockets[i];
if (FD_ISSET(sd, &read_fds)) {
if (handle_request(sd) < 0) {
close(sd);
client_sockets[i] = 0;
} else {
response_count++;
}
}
}
// 每 100 次请求输出一次指标值
request_count++;
if (request_count % 100 == 0) {
printf("Request count: %d, Response count: %d, Success rate: %.2f%%\n", request_count, response_count, (float)response_count / request_count * 100);
}
}
close_server();
return 0;
}
// 初始化服务器
int init_server() {
struct sockaddr_in server_addr;
int opt = 1;
// 创建监听套接字
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
return -1;
}
// 设置套接字选项
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0) {
perror("setsockopt");
return -1;
}
// 绑定地址和端口
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
perror("bind failed");
return -1;
}
// 监听套接字
if (listen(server_fd, 5) < 0) {
perror("listen failed");
return -1;
}
return 0;
}
// 接受新连接
int accept_connections() {
int i, client_socket;
struct sockaddr_in client_addr;
int client_len = sizeof(client_addr);
if ((client_socket = accept(server_fd, (struct sockaddr *)&client_addr, (socklen_t *)&client_len)) < 0) {
perror("accept failed");
return -1;
}
// 将客户端套接字添加到列表中
for (i = 0; i < max_clients; i++) {
if (client_sockets[i] == 0) {
client_sockets[i] = client_socket;
break;
}
}
return 0;
}
// 处理客户端请求
int handle_request(int client_socket) {
char request[MAX_REQUEST_SIZE] = {0};
int read_len = read(client_socket, request, MAX_REQUEST_SIZE);
if (read_len <= 0) {
return -1;
}
// 发送响应消息体
return send_response(client_socket);
}
// 发送响应消息体
int send_response(int client_socket) {
int i, sent_len = 0;
while (sent_len < response_size) {
i = send(client_socket, response_template + sent_len, response_size - sent_len, 0);
if (i < 0) {
return -1;
}
sent_len += i;
}
return 0;
}
// 关闭服务器
void close_server() {
int i;
close(server_fd);
for (i = 0; i < max_clients; i++) {
if (client_sockets[i] > 0) {
close(client_sockets[i]);
}
}
}
// 获取指定范围内的随机数
int get_random_number(int min, int max) {
return (rand() % (max - min + 1)) + min;
}
```
在上述代码中,我们使用了 `select()` 函数来同时处理多个连接。每当有新的连接请求到来时,我们将其添加到一个客户端套接字列表中,并使用 `select()` 函数等待这些套接字上的数据可读。每当某个套接字上有数据可读时,我们就可以处理客户端发送的请求并发送响应消息体。同时,在主循环中,我们还可以输出一些指标值,例如请求数量、响应数量和成功率等。
我们还提供了一个用于随机产生一些请求的函数 `get_random_number()`,可以用于测试服务器在高负载情况下的性能。
在编译并运行该程序后,我们可以使用一些压力测试工具(例如 Apache Bench)对其进行压力测试,同时观察输出的指标值,以评估服务器的性能。
阅读全文