⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 web_server.c

📁 linux下开发的web服务器
💻 C
字号:
/* web_server.c */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <netdb.h>#include <sys/stat.h>#include <string.h>#define MAX_QUE_CONN_NM		5int start_server(int portnum);int ignore_others(FILE *fp);int process_request(char *rq, int fd);int resp_cannot_do(int fd);int resp_not_exist(char *fn);int resp_do_404(char *item, int fd);char *get_filename_extension(char *fn); int is_a_dir(char *fn);int is_a_cgi_file(char *fn);int resp_do_ls(char *dir, int fd);int resp_do_exec(char *prog, int fd);int resp_do_cat(char *fn, int fd);int main(int argc, char *argv[]){	int sock, fd;	FILE *fpin;	char request[BUFSIZ];	if(argc == 1)	{		fprintf(stderr, "usage: ./web_server portnum\n");		exit(1);	}	if ((sock = start_server(atoi(argv[1]))) < 0)	{		perror("start_server");		exit(1);	}		while(1)	{		fd = accept(sock, NULL, NULL); /* 接收请求 */		fpin = fdopen(fd, "r"); 		fgets(request, BUFSIZ, fpin); /* 读取客户端的请求 */ 		ignore_others(fpin); /* 跳过其他命令 */		process_request(request, fd); /* 接收客户端的请求 */		fclose(fpin);	}	exit(0);}/* 启动服务器 */int start_server(int portnum){	struct sockaddr_in server_sockaddr, client_sockaddr;	int sin_size, recvbytes;			int sockfd, client_fd;		/*建立socket连接*/	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)	{		perror("socket");		return -1;	}	int i = 1;/* 使得重复使用本地地址与套接字进行绑定 */			setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));	/*设置sockaddr_in 结构体中相关参数*/	server_sockaddr.sin_family = AF_INET;		server_sockaddr.sin_port = htons(portnum);		server_sockaddr.sin_addr.s_addr = INADDR_ANY;			bzero(&(server_sockaddr.sin_zero), 8);			/* 调用绑定函数 */	if (bind(sockfd, (struct sockaddr *)&server_sockaddr, sizeof(struct sockaddr)) == -1)	{		perror("bind");		return -1;	}	if (listen(sockfd, MAX_QUE_CONN_NM) == -1) /* 调用listen函数*/	{		perror("listen");		return -1;	}	return sockfd;}/* 跳过其他命令 */int ignore_others(FILE *fp){	char buf[BUFSIZ];	while(fgets(buf, BUFSIZ, fp) != NULL && strcmp(buf,"\r\n") != 0);	return 0;}/* 处理请求包 */int process_request(char *rq, int fd){	char cmd[BUFSIZ], arg[BUFSIZ];	if (fork() != 0)	{		return 1; /*父进程立即返回,子进程继续往下执行*/	}		strcpy(arg, "./");	if(sscanf (rq, "%s %s", cmd, arg + 2) != 2) /* 解析请求行 */	{		return 1;	}	if (strcmp(cmd, "GET") != 0) /* 只处理GET方法 */	{		resp_cannot_do(fd);	}	else if (not_exist(arg)) /* 若请求的资源不存在则返回失败信息 */	{		resp_do_404(arg,fd);	}	else if (is_a_dir(arg)) /* 若请求的资源是一个目录则列出目录内容 */	{		resp_do_ls(arg, fd);	}	else if (is_a_cgi_file(arg)) /* 若请求的资源是一个.cgi文件则运行它 */	{		resp_do_exec(arg, fd);	}	else /* 若是其他文件,则表示它,文本/图像/声音 */	{		resp_do_cat(arg, fd);							}	return 0;}/* 打报头 */int pack_header(FILE *fp, char *content_type){	fprintf(fp, "HTTP/1.0 200 ok\r\n");		if (content_type)	{		fprintf(fp, "Content-type:%s\r\n", content_type);		return 0;	}	return 1;}/* 未定义P命令的处理方法 */int resp_cannot_do(int fd){	FILE *fp = fdopen(fd, "w");	fprintf(fp, "HTTP/1.1 501 Not Implemented\r\n");	fprintf(fp, "Content-type: text/plain\r\n");	fprintf(fp, "\r\n");	fprintf(fp, "That command is not yet implemented\r\n");	fclose(fp);	return 0;}/* 判断资源是否存在 */int not_exist(char *fn){      struct stat info;      return (stat(fn, &info) == -1);}/* 用户请求的资源不存在时处理方法 */int resp_do_404(char *item, int fd){	FILE *fp = fdopen(fd, "w");	fprintf(fp, "HTTP/1.1 404 Not Found\r\n");	fprintf(fp, "Content-type: text/plain\r\n");	fprintf(fp, "\r\n");	fprintf(fp, "The item you requested: %s\r\nis not found\r\n", item);	fclose(fp);	return 0;}char *get_filename_extension(char *fn) {    char *cp;    if ((cp = strrchr(fn, '.')) != NULL)	{		return (cp + 1);	}	return NULL;}/* 判断用户请求的资源是否一个目录 */int is_a_dir(char *fn){	struct stat info;	return (stat(fn, &info) != -1 && S_ISDIR(info.st_mode));}/* 判断用户请求的资源是否一个cgi文件 */int is_a_cgi_file(char *fn){	return (strcmp(get_filename_extension(fn), "cgi") == 0);}/* 处理列出目录信息的请求 */int resp_do_ls(char *dir, int fd){	FILE *fp = fdopen(fd, "w");		/* 打开套接字 */	pack_header(fp, "text/plain"); /*向客户端发送状态行和实体头信息*/	fprintf(fp, "\r\n");	fflush(fp);		dup2(fd, 1);	/*把套接字绑定到标准输出*/	dup2(fd, 2);	/*把套接字绑定到标准出错*/	close(fd);	execlp("ls", "ls", "-l", dir, NULL); /*执行“ls -l”*/	perror(dir);	return 0;}/* 处理执行一个可执行程序的请求 */int resp_do_exec(char *prog, int fd){	FILE *fp = fdopen(fd, "w");		/* 打开套接字 */	pack_header(fp, NULL);			/*向客户端发送状态行和实体头信息*/	fflush(fp);	dup2(fd,1);						/*把套接字绑定到标准输出*/	dup2(fd,2);						/*把套接字绑定到标准出错*/	close(fd);	execl(prog, prog, NULL);	perror(prog);	return 0;}/* 处理显示一个文件的请求 */int resp_do_cat(char *fn, int fd){	char *extension = get_filename_extension(fn); /* 获得文件扩展名 */	char *content = "text/plain"; /* 默认为显示文本文件 */	FILE *fpsock, *fpfile;	int c;	/* 根据文件的扩展名判断文件的类型 */	if (strcmp(extension, "html") == 0)	{		content = "text/html"; /* 显示网页 */	}	else if (strcmp(extension, "gif") == 0)	{		content = "image/gif"; /* 显示gif文件 */	}	else if (strcmp(extension, "jpg") == 0)	{		content = "image/jpg"; /* 显示jpg文件 */	}	else if (strcmp(extension, "jpeg") == 0)	{		content = "image/jpeg"; /* 显示jpeg文件 */	}	fpsock = fdopen(fd, "w");	fpfile = fopen(fn, "r");	if (fpsock != NULL && fpfile != NULL)	{		pack_header(fpsock, content);		fprintf(fpsock, "\r\n");				while ((c = getc(fpfile)) != EOF)		{			putc(c, fpsock);		}		fclose(fpfile);		fclose(fpsock);			return 0;	}	return 1;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -