完成基础的tcp连接,支持基础的client与其连接 使用fork()来支持并发访问服务器 简单的http访问,支持静态页面访问 支持静态页面访问,需要一定的报错机制,如404页面的建立。 1. socket实现简单Http服务器,完成html的解析; 2. 运行该服务器可以通过浏览器访问服务器目录下的 Html文件、jpg图片、css文件的载入。 完成初步的Http服务器功能。并实现多线程访问 C语言实现Web服务器
时间: 2024-02-13 15:06:06 浏览: 59
以下是一个简单的基于 TCP 的 HTTP 服务器示例,支持静态页面访问和多线程访问:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <fcntl.h>
#define MAXLINE 1024
#define PORT 8080
#define SERVER_NAME "WebServer"
#define DOCUMENT_ROOT "/var/www"
void handle_connection(int sockfd) {
int n;
char buf[MAXLINE];
char filename[MAXLINE];
char uri[MAXLINE];
char method[MAXLINE];
char http_version[MAXLINE];
char content_type[MAXLINE];
char response[MAXLINE];
char path[MAXLINE];
int fd;
struct stat st;
n = read(sockfd, buf, MAXLINE);
if (n <= 0) {
return;
}
sscanf(buf, "%s %s %s", method, uri, http_version);
sprintf(filename, "%s%s", DOCUMENT_ROOT, uri);
if (strcmp(method, "GET") != 0) {
sprintf(response, "HTTP/1.0 501 Not Implemented\r\n");
send(sockfd, response, strlen(response), 0);
return;
}
if (stat(filename, &st) < 0) {
sprintf(response, "HTTP/1.0 404 Not Found\r\n");
send(sockfd, response, strlen(response), 0);
return;
}
if (S_ISDIR(st.st_mode)) {
sprintf(path, "%s/index.html", filename);
if (stat(path, &st) < 0) {
sprintf(response, "HTTP/1.0 404 Not Found\r\n");
send(sockfd, response, strlen(response), 0);
return;
}
sprintf(filename, "%s", path);
}
if (strstr(filename, ".html")) {
sprintf(content_type, "text/html");
} else if (strstr(filename, ".jpg")) {
sprintf(content_type, "image/jpeg");
} else if (strstr(filename, ".css")) {
sprintf(content_type, "text/css");
} else {
sprintf(content_type, "text/plain");
}
sprintf(response, "HTTP/1.0 200 OK\r\nContent-type: %s\r\n\r\n", content_type);
send(sockfd, response, strlen(response), 0);
if ((fd = open(filename, O_RDONLY)) < 0) {
return;
}
while ((n = read(fd, buf, MAXLINE)) > 0) {
send(sockfd, buf, n, 0);
}
close(fd);
}
int main() {
int listenfd, connfd;
pid_t pid;
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
listen(listenfd, 5);
while (1) {
clilen = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
if ((pid = fork()) == 0) {
close(listenfd);
handle_connection(connfd);
close(connfd);
exit(0);
}
close(connfd);
waitpid(-1, NULL, WNOHANG);
}
return 0;
}
```
这个程序的主要逻辑是在 `handle_connection` 函数中实现的,用来处理接收到的 HTTP 请求。首先读取请求的方法、URI 和 HTTP 版本号,并拼接出请求的文件名。如果方法不是 GET 方法,则返回 501 Not Implemented;如果文件不存在,则返回 404 Not Found。然后判断文件类型,并返回相应的 Content-type。最后读取文件内容并发送给客户端。
在主函数中,首先创建一个监听套接字并绑定到指定端口。然后进入循环,等待客户端连接。在接收到连接请求后,使用 `fork()` 函数创建一个子进程来处理请求。父进程继续等待下一个连接请求。子进程关闭监听套接字,调用 `handle_connection` 函数处理请求,并关闭连接套接字,最后退出。为了防止僵尸进程的产生,父进程在处理完一个连接请求后使用 `waitpid()` 函数回收子进程。
阅读全文