linuxIO复用搭建webserver

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

#define PORT 8080
#define MAX_CLIENTS 30
#define BUFFER_SIZE 1024

void handle_client_request(int client_socket) {
char buffer[BUFFER_SIZE] = {0};
int valread = read(client_socket, buffer, BUFFER_SIZE);
if (valread <= 0) {
perror(“Error reading request from client”);
return;
}

// Parse HTTP request (simplified for demonstration)
printf("Request received:\n%s\n", buffer);

// Simulate handling GET and POST requests
const char *response_message = "HTTP/1.1 200 OK\nContent-Type: text/plain\n\nHello from C Web Server\n";
write(client_socket, response_message, strlen(response_message));

}

int main() {
int server_fd, client_sockets[MAX_CLIENTS], max_clients = MAX_CLIENTS;
struct sockaddr_in address;
int addrlen = sizeof(address);

// Create socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
    perror("Socket creation failed");
    exit(EXIT_FAILURE);
}

// Set socket options to allow multiple connections
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &(int){1}, sizeof(int)) < 0) {
    perror("Setsockopt failed");
    exit(EXIT_FAILURE);
}

address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);

// Bind the socket to localhost port 8080
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
    perror("Bind failed");
    exit(EXIT_FAILURE);
}

// Listen for incoming connections
if (listen(server_fd, 3) < 0) {
    perror("Listen failed");
    exit(EXIT_FAILURE);
}

// Initialize client_sockets array
for (int i = 0; i < max_clients; i++) {
    client_sockets[i] = 0;
}

while (1) {
    fd_set readfds;
    int max_sd, activity;

    FD_ZERO(&readfds);
    FD_SET(server_fd, &readfds);
    max_sd = server_fd;

    // Add child sockets to set
    for (int i = 0; i < max_clients; i++) {
        int sd = client_sockets[i];

        if (sd > 0) {
            FD_SET(sd, &readfds);
        }

        if (sd > max_sd) {
            max_sd = sd;
        }
    }

    // Wait for activity on any of the sockets
    activity = select(max_sd + 1, &readfds, NULL, NULL, NULL);

    if ((activity < 0) && (errno != EINTR)) {
        perror("Select error");
    }

    // If activity is on the server socket, it's an incoming connection
    if (FD_ISSET(server_fd, &readfds)) {
        int new_socket;
        if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
            perror("Accept error");
            exit(EXIT_FAILURE);
        }

        printf("New connection, socket fd is %d, ip is : %s, port : %d\n",
               new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port));

        // Add new socket to array of client sockets
        for (int i = 0; i < max_clients; i++) {
            if (client_sockets[i] == 0) {
                client_sockets[i] = new_socket;
                break;
            }
        }
    }

    // Check for IO operation on other sockets
    for (int i = 0; i < max_clients; i++) {
        int sd = client_sockets[i];

        if (FD_ISSET(sd, &readfds)) {
            handle_client_request(sd);
            close(sd);
            client_sockets[i] = 0;  // Reset socket descriptor in array
        }
    }
}

return 0;

}

保证图片也正常传输

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SERVER_PORT 8080
#define MAX_REQUEST_SIZE 2048
#define MAX_THREADS 10

// HTTP response statuses
#define STATUS_OK 200
#define STATUS_NOT_FOUND 404
#define STATUS_INTERNAL_SERVER_ERROR 500

// HTTP request methods
#define METHOD_GET 1
#define METHOD_POST 2

// Structure to handle HTTP request and response
typedef struct {
int method;
char uri[1024];
char body[MAX_REQUEST_SIZE];
} HttpRequest;

typedef struct {
int status;
char message[1024];
char body[MAX_REQUEST_SIZE];
} HttpResponse;

// Function prototypes
void *handle_client(void *arg);
int parse_http_request(char *request_str, HttpRequest *request);
void process_request(HttpRequest *request, HttpResponse *response);
void send_response(int client_socket, HttpResponse *response);
void load_file_content(const char *filename, char *content, size_t max_size);

// Main function
int main() {
// … (unchanged)

pthread_t thread_id;
int thread_count = 0;

// ... (unchanged)

while (1) {
    // ... (unchanged)

    if (pthread_create(&thread_id, NULL, handle_client, (void *)&client_socket) != 0) {
        perror("Error creating thread");
        close(client_socket);
        continue;
    }

    // ... (unchanged)
}

// ... (unchanged)

}

// Function to handle client requests
void *handle_client(void *arg) {
// … (unchanged)

// Receive request from client
// ... (unchanged)

// Parse HTTP request
// ... (unchanged)

// Process HTTP request
process_request(&http_request, &http_response);

// Send HTTP response
send_response(client_socket, &http_response);

// Clean up and exit thread
close(client_socket);
pthread_exit(NULL);

}

// Parse HTTP request and fill HttpRequest struct
int parse_http_request(char *request_str, HttpRequest *request) {
// … (unchanged)
}

// Process HTTP request and prepare HTTP response
void process_request(HttpRequest *request, HttpResponse *response) {
// Handle GET requests
if (request->method == METHOD_GET) {
if (strcmp(request->uri, “/”) == 0) {
// Handle root request with HTML content
response->status = STATUS_OK;
snprintf(response->message, sizeof(response->message), “OK”);
snprintf(response->body, sizeof(response->body), “

Hello, World!

”);
} else {
// Check if requesting an image file
if (strstr(request->uri, “.jpg”) || strstr(request->uri, “.jpeg”) || strstr(request->uri, “.png”)) {
// Load image file
char filename[256]; // Adjust size as needed
snprintf(filename, sizeof(filename), “.%s”, request->uri); // Assuming images are in current directory
load_file_content(filename, response->body, sizeof(response->body));
if (strlen(response->body) > 0) {
response->status = STATUS_OK;
snprintf(response->message, sizeof(response->message), “OK”);
} else {
response->status = STATUS_NOT_FOUND;
snprintf(response->message, sizeof(response->message), “Not Found”);
snprintf(response->body, sizeof(response->body), “

404 Not Found

”);
}
} else {
// Handle other types of requests (e.g., static files)
// Example: serve static files like CSS, JS, etc.
// For simplicity, this example assumes they are served from local directory.
// Additional security and MIME type handling is recommended.
char filename[256]; // Adjust size as needed
snprintf(filename, sizeof(filename), “.%s”, request->uri); // Assuming files are in current directory
load_file_content(filename, response->body, sizeof(response->body));
if (strlen(response->body) > 0) {
response->status = STATUS_OK;
snprintf(response->message, sizeof(response->message), “OK”);
} else {
response->status = STATUS_NOT_FOUND;
snprintf(response->message, sizeof(response->message), “Not Found”);
snprintf(response->body, sizeof(response->body), “

404 Not Found

”);
}
}
}
} else if (request->method == METHOD_POST) {
// Handle POST request (echo back the received data)
// … (unchanged)
} else {
response->status = STATUS_NOT_FOUND;
snprintf(response->message, sizeof(response->message), “Not Found”);
snprintf(response->body, sizeof(response->body), “

404 Not Found

”);
}
}

// Send HTTP response to client
void send_response(int client_socket, HttpResponse *response) {
// … (unchanged)
}

// Load content of a file into a buffer
void load_file_content(const char *filename, char *content, size_t max_size) {
FILE *file = fopen(filename, “rb”);
if (file != NULL) {
fseek(file, 0, SEEK_END);
long file_size = ftell(file);
if (file_size > 0 && file_size < max_size) {
fseek(file, 0, SEEK_SET);
fread(content, file_size, 1, file);
content[file_size] = ‘\0’;
}
fclose(file);
}
}

v2.0 epoll

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

#define MAX_EVENTS 10
#define BUFFER_SIZE 1024
#define PORT 8080

void handle_request(int sockfd, char *request) {
// 处理HTTP请求
// 这里可以实现简单的GET和POST请求处理逻辑
// 在此简化处理,可以根据需求扩展功能
}

void send_response(int sockfd, char *response) {
// 发送HTTP响应
// 可以根据具体需要构造响应头部和响应内容
// 这里简化为直接发送固定的响应内容
char *header = “HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n”;
write(sockfd, header, strlen(header));
write(sockfd, response, strlen(response));
}

int main() {
int server_fd, epoll_fd, event_count;
struct sockaddr_in address;
struct epoll_event event, events[MAX_EVENTS];
socklen_t addrlen = sizeof(address);
char buffer[BUFFER_SIZE];

// 创建服务器端socket
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
    perror("socket failed");
    exit(EXIT_FAILURE);
}

// 设置服务器socket地址和端口
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);

// 绑定服务器socket到指定端口
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
    perror("bind failed");
    exit(EXIT_FAILURE);
}

// 监听入站连接
if (listen(server_fd, 3) < 0) {
    perror("listen");
    exit(EXIT_FAILURE);
}

// 创建 epoll 实例
if ((epoll_fd = epoll_create1(0)) < 0) {
    perror("epoll_create1");
    exit(EXIT_FAILURE);
}

// 将服务器socket添加到 epoll 实例中监听读取事件
event.events = EPOLLIN;
event.data.fd = server_fd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) < 0) {
    perror("epoll_ctl");
    exit(EXIT_FAILURE);
}

printf("Server listening on port %d \n", PORT);

// 主循环
while (1) {
    event_count = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
    if (event_count < 0) {
        perror("epoll_wait");
        exit(EXIT_FAILURE);
    }

    for (int i = 0; i < event_count; ++i) {
        int sockfd = events[i].data.fd;

        // 处理新的入站连接
        if (sockfd == server_fd) {
            int new_socket = accept(server_fd, (struct sockaddr *)&address, &addrlen);
            if (new_socket < 0) {
                perror("accept");
                exit(EXIT_FAILURE);
            }
            printf("New connection, socket fd is %d, ip is : %s, port : %d\n", new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port));

            // 将新连接的socket添加到 epoll 实例中监听读取事件
            event.events = EPOLLIN;
            event.data.fd = new_socket;
            if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_socket, &event) < 0) {
                perror("epoll_ctl");
                exit(EXIT_FAILURE);
            }
        } else { // 处理现有连接上的数据读取事件
            int valread = read(sockfd, buffer, BUFFER_SIZE);
            if (valread == 0) {
                // 客户端断开连接
                close(sockfd);
                epoll_ctl(epoll_fd, EPOLL_CTL_DEL, sockfd, NULL);
            } else {
                // 处理客户端请求
                handle_request(sockfd, buffer);
                // 发送响应(这里假设直接发送固定响应)
                send_response(sockfd, "<html><body><h1>Hello, World!</h1></body></html>");
            }
        }
    }
}

close(server_fd);
return 0;

}

仅有目录时返回index.html

void handle_request(int client_fd, char *request) {
char method[10], path[50], protocol[10];
sscanf(request, “%s %s %s”, method, path, protocol);

// Check if path is "/"
if (strcmp(path, "/") == 0) {
    // Try to serve index.html or Index.html
    if (access("index.html", F_OK) != -1) {
        // index.html exists
        serve_file(client_fd, "index.html");
    } else if (access("Index.html", F_OK) != -1) {
        // Index.html exists
        serve_file(client_fd, "Index.html");
    } else {
        // Neither file exists, return 404
        char response[MAXLINE];
        sprintf(response, "HTTP/1.1 404 Not Found\r\n"
                          "Content-Type: text/plain\r\n"
                          "\r\n"
                          "404 Not Found: File not found");
        send_response(client_fd, response);
    }
} else {
    // Process other paths normally
    if (strcasecmp(method, "GET") == 0) {
        printf("Received GET request for %s\n", path);
        serve_file(client_fd, path + 1); // Skip leading '/'
    } else {
        // Unsupported method
        printf("Unsupported request method: %s\n", method);
        char response[MAXLINE];
        sprintf(response, "HTTP/1.1 501 Not Implemented\r\n"
                          "Content-Type: text/plain\r\n"
                          "\r\n"
                          "Unsupported request method");
        send_response(client_fd, response);
    }
}

}

void serve_file(int client_fd, char *filename) {
FILE *file = fopen(filename, “r”);
if (file != NULL) {
char response[MAXLINE];
sprintf(response, “HTTP/1.1 200 OK\r\n”
“Content-Type: text/html\r\n”
“\r\n”);

    send_response(client_fd, response);

    // Send file contents
    char buffer[MAXLINE];
    size_t bytes_read;
    while ((bytes_read = fread(buffer, 1, sizeof(buffer), file)) > 0) {
        if (write(client_fd, buffer, bytes_read) == -1) {
            perror("write");
            exit(EXIT_FAILURE);
        }
    }

    fclose(file);
} else {
    // File not found
    char response[MAXLINE];
    sprintf(response, "HTTP/1.1 404 Not Found\r\n"
                      "Content-Type: text/plain\r\n"
                      "\r\n"
                      "404 Not Found: File not found");
    send_response(client_fd, response);
}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值