#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 <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/sendfile.h>
#define PORT 8080
#define BUFFER_SIZE 4096
const char *get_content_type(const char *path) {
const char *last_dot = strrchr(path, '.');
if (last_dot) {
if (strcmp(last_dot, ".html") == 0) return "text/html";
if (strcmp(last_dot, ".txt") == 0) return "text/plain";
if (strcmp(last_dot, ".js") == 0) return "application/javascript";
if (strcmp(last_dot, ".css") == 0) return "text/css";
if (strcmp(last_dot, ".jpg") == 0) return "image/jpeg";
if (strcmp(last_dot, ".jpeg") == 0) return "image/jpeg";
if (strcmp(last_dot, ".png") == 0) return "image/png";
if (strcmp(last_dot, ".gif") == 0) return "image/gif";
if (strcmp(last_dot, ".ico") == 0) return "image/x-icon";
}
return "application/octet-stream";
}
// 发送HTTP响应
void send_response(int client_fd, int status, const char *status_msg,
const char *content_type, const char *body, size_t body_len) {
char header[BUFFER_SIZE];
// 构建响应头
int header_len = snprintf(header, sizeof(header),
"HTTP/1.1 %d %s\r\n"
"Content-Type: %s\r\n"
"Content-Length: %zu\r\n"
"Connection: close\r\n"
"\r\n",
status, status_msg, content_type, body_len);
// 发送响应头
write(client_fd, header, header_len);
// 发送响应体
if (body_len > 0) {
write(client_fd, body, body_len);
}
}
// 发送文件内容
void send_file(int client_fd, const char *file_path) {
char buffer[BUFFER_SIZE];
int file_fd = open(file_path, O_RDONLY);
if (file_fd < 0) {
// 文件不存在
const char *not_found = "<html><body><h1>404 Not Found</h1></body></html>";
send_response(client_fd, 404, "Not Found", "text/html", not_found, strlen(not_found));
return;
}
// 获取文件大小
struct stat file_stat;
fstat(file_fd, &file_stat);
off_t file_size = file_stat.st_size;
// 获取内容类型
const char *content_type = get_content_type(file_path);
// 发送响应头
char header[BUFFER_SIZE];
int header_len = snprintf(header, sizeof(header),
"HTTP/1.1 200 OK\r\n"
"Content-Type: %s\r\n"
"Content-Length: %ld\r\n"
"Connection: close\r\n"
"\r\n",
content_type, file_size);
write(client_fd, header, header_len);
off_t offset = 0;
ssize_t sentbytes;
// fasong
while(offset < file_size){
sentbytes = sendfile(client_fd,file_fd,&offset,file_size - offset);
if(sentbytes <= 0){
perror("sendfile");
break;
}
offset += sentbytes;
}
close(file_fd);
}
int main() {
int server_fd, client_fd;
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len = sizeof(client_addr);
char buffer[BUFFER_SIZE] = {0};
// 创建套接字
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// 设置端口复用,避免重启时地址被占用
int opt = 1;
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
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");
exit(EXIT_FAILURE);
}
// 监听
if (listen(server_fd, 10) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
printf("Server listening on port %d\n", PORT);
while (1) {
// 接受连接
if ((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &addr_len)) < 0) {
perror("accept");
continue;
}
// 读取请求
ssize_t bytes_read = read(client_fd, buffer, BUFFER_SIZE - 1);
if (bytes_read < 0) {
perror("read");
close(client_fd);
continue;
}
buffer[bytes_read] = '\0';
// 解析请求行(第一行)
char method[16], path[256];
sscanf(buffer, "%s %s", method, path);
// 只处理GET请求
if (strcmp(method, "GET") != 0) {
close(client_fd);
continue;
}
// 如果请求根路径,则默认返回index.html
if (strcmp(path, "/") == 0) {
strcpy(path, "/index.html");
}
// 去掉路径开头的'/',得到相对路径
char file_path[512];
snprintf(file_path, sizeof(file_path), ".%s", path);
// 尝试打开文件
int file_fd = open(file_path, O_RDONLY);
if (file_fd < 0) {
// 文件不存在,返回404
const char *not_found_response =
"HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n"
"\r\n"
"<html><body><h1>404 Not Found</h1></body></html>";
write(client_fd, not_found_response, strlen(not_found_response));
close(client_fd);
continue;
}
// 获取文件信息(主要是文件大小)
struct stat file_stat;
fstat(file_fd, &file_stat);
off_t file_size = file_stat.st_size;
// 获取内容类型
const char *content_type = get_content_type(file_path);
// 构建响应头
char header[BUFFER_SIZE];
int header_len = snprintf(header, sizeof(header),
"HTTP/1.1 200 OK\r\n"
"Content-Type: %s\r\n"
"Content-Length: %ld\r\n"
"Connection: close\r\n"
"\r\n",
content_type, file_size);
// 发送响应头
write(client_fd, header, header_len);
// 发送文件内容
ssize_t bytes_sent;
while ((bytes_sent = send_file(client_fd, file_path) > 0) {
// 使用sendfile高效发送文件
}
// 关闭文件和客户端连接
close(file_fd);
close(client_fd);
}
close(server_fd);
return 0;
}检查这段代码的错误
最新发布