#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);
}
}