完成基础的tcp连接,支持基础的client与其连接 使用fork()来支持并发访问服务器 简单的http访问,支持静态页面访问 支持静态页面访问,需要一定的报错机制,如404页面的建立。 1. socket实现简单Http服务器,完成html的解析; 2. 运行该服务器可以通过浏览器访问服务器目录下的 Html文件、jpg图片、css文件的载入。 完成初步的Http服务器功能。
时间: 2024-01-24 17:17:28 浏览: 79
好的,那我们可以先从最基础的开始,逐步实现一个简单的HTTP服务器。
首先,我们需要创建一个TCP连接来实现客户端与服务器之间的通信。以下是一个简单的TCP服务器代码示例,可以在Linux系统下运行:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define SERVER_PORT 8080
#define MAX_CLIENTS 10
int main() {
int server_fd, client_fd;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
// 创建套接字
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
// 设置服务器地址
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(SERVER_PORT);
// 绑定套接字到服务器地址
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
// 监听套接字
if (listen(server_fd, MAX_CLIENTS) == -1) {
perror("listen");
exit(EXIT_FAILURE);
}
printf("Server listening on port %d...\n", SERVER_PORT);
while (1) {
// 接受客户端连接请求
if ((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len)) == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
printf("Client connected: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
// 处理客户端请求
close(client_fd);
}
close(server_fd);
return 0;
}
```
这个代码创建了一个TCP服务器,绑定到8080端口,并监听来自最多10个客户端的请求。当有客户端连接时,它将打印客户端的IP地址和端口号,并关闭连接。
接下来,我们需要使用fork()函数来支持并发访问服务器。当有新的客户端连接时,我们可以创建一个新的子进程来处理客户端请求。以下是修改后的代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define SERVER_PORT 8080
#define MAX_CLIENTS 10
void handle_client(int client_fd, struct sockaddr_in client_addr) {
printf("Client connected: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
// 处理客户端请求
close(client_fd);
}
int main() {
int server_fd, client_fd;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
// 创建套接字
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
// 设置服务器地址
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(SERVER_PORT);
// 绑定套接字到服务器地址
if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
// 监听套接字
if (listen(server_fd, MAX_CLIENTS) == -1) {
perror("listen");
exit(EXIT_FAILURE);
}
printf("Server listening on port %d...\n", SERVER_PORT);
while (1) {
// 接受客户端连接请求
if ((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len)) == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
pid_t pid = fork();
if (pid == -1) {
close(client_fd);
} else if (pid == 0) {
close(server_fd);
handle_client(client_fd, client_addr);
exit(EXIT_SUCCESS);
} else {
close(client_fd);
}
}
close(server_fd);
return 0;
}
```
现在,我们可以使用fork()函数来支持多个客户端的并发访问了。
接下来,我们可以开始实现静态页面的访问。我们需要修改handle_client()函数来处理HTTP请求,并返回相应的静态页面。以下是一个简单的handle_client()函数代码示例:
```c
void handle_client(int client_fd, struct sockaddr_in client_addr) {
printf("Client connected: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
char buffer[1024];
ssize_t n;
// 读取HTTP请求
n = read(client_fd, buffer, sizeof(buffer));
if (n == -1) {
perror("read");
exit(EXIT_FAILURE);
}
// 打印HTTP请求
printf("HTTP request:\n%s\n", buffer);
// 解析HTTP请求
char method[10], path[1024], protocol[10];
sscanf(buffer, "%s %s %s", method, path, protocol);
// 构造HTTP响应
char response[1024];
char *content_type;
FILE *file;
if (strcmp(path, "/") == 0) {
file = fopen("index.html", "r");
content_type = "text/html";
} else if (strcmp(path, "/style.css") == 0) {
file = fopen("style.css", "r");
content_type = "text/css";
} else if (strcmp(path, "/image.jpg") == 0) {
file = fopen("image.jpg", "rb");
content_type = "image/jpeg";
} else {
file = fopen("404.html", "r");
content_type = "text/html";
}
if (file == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
fseek(file, 0, SEEK_END);
long file_size = ftell(file);
rewind(file);
sprintf(response, "HTTP/1.1 200 OK\r\nContent-Type: %s\r\nContent-Length: %ld\r\n\r\n", content_type, file_size);
// 发送HTTP响应头
n = write(client_fd, response, strlen(response));
if (n == -1) {
perror("write");
exit(EXIT_FAILURE);
}
// 发送HTTP响应体
char file_buffer[1024];
size_t bytes_read;
while ((bytes_read = fread(file_buffer, 1, sizeof(file_buffer), file)) > 0) {
n = write(client_fd, file_buffer, bytes_read);
if (n == -1) {
perror("write");
exit(EXIT_FAILURE);
}
}
fclose(file);
close(client_fd);
}
```
这个函数会读取客户端发送的HTTP请求,解析出请求方法、路径和协议版本,并根据路径返回相应的静态页面。如果路径不存在,则返回一个404页面。
现在,我们已经实现了一个简单的HTTP服务器,可以通过浏览器访问服务器目录下的html文件、jpg图片和css文件了。
阅读全文