tinyhttpd项目详解以及遇到的一些问题

目录

仿照tinyhttpd项目写的,每个函数的实现可能有一些不一样,不过大体的函数功能是一样的

阅读代码的顺序为:

main()——>startup()——>accept_request()——>serve_file()——>execute_cig()。

流程图如下:

流程图

cgi模块执行原理

cgi执行原理
图例解释:定义两个管道input,output,
input:由父进程向子进程的输入管道
output:由子进程向父进程的输出管道
1、让子进程去执行cgi,父进程去做I/O操作。首先将子进程的标准输入重定向为input[0],将子进程的标准输出重定向为output[1],这样,子进程的输入来自父进程,子进程的输出是输出到父进程。通过管道进行父子进程的通信。
2、父进程通过recv接收来自客户端的表单输入,并且通过write传给子进程,子进程收到父进程的输入后,执行cgi脚本,执行完后,输出给父进程。父进程通过read读取到子进程的输出后,再通过send发送到客户端。

代码如下:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/wait.h>
#include <sys/stat.h>

#define SERVER_STRING "Server: tinyhttpd/1.0.0\r\n"
#define STDIN 0
#define STDOUT 1
#define STDERR 2

// 用来初始化服务器端socket
int startup(int *port);

// 用来输出错误情况
void error_die(const char *str);

// 用来处理请求
void *accept_request(void* client);

// 用来处理错误的请求方法
void unimplemented(int client_sock);

// 用来处理404错误
void not_found(int client_sock);

// 这个函数用来读取一行http请求,并把结尾的'\r\n'替换成'\n'
int get_line(int sock, char *buf, int size);

// 传递请求的页面给客户端
void server_file(int sock, char *path);

// 用来添加http响应头部
void headers(int sock);

// 用来发送响应实体
void cat(int client_sock, FILE *file);

// 用来执行cgi脚本
void execute_cgi(int client_sock, const char *path, const char *method, const char *query_string);

// 处理错误的请求
void bad_request(int sock);

// 处理内部错误的情况
void cannot_execute(int sock);

int main(void)
{
   
	int server_sock, client_sock;
	struct sockaddr_in client_addr;

	socklen_t client_addr_size;
	pthread_t newthread;
	
	int port = 12345;
	// 初始化服务器端socket
	server_sock = startup(&port);
	printf("httpd start port: %d...\n",port);
	
	while(1)
	{
   
		// 建立一个新的客户端连接
		client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &client_addr_size);
		if(client_sock == -1)
			error_die("accept");
		// 每来一个客户端连接,就创建一个线程来处理请求
		if(pthread_create(&newthread, NULL, accept_request, (void*)&client_sock) != 0)
			error_die("pthread_create");
	}
	close(server_sock);
	return 0;
}

int startup(int *port)
{
   
	struct sockaddr_in serv_addr;
	int serv_sock;
	int on = 1;
	
	//int port = 12345; // 端口
	//char *ip = "172.22.29.7"; // ip
	serv_sock = socket(PF_INET, SOCK_STREAM, 0);// 创建服务器端套接字
	if(serv_sock == -1)
		error_die("socket");
	
	memset(&serv_addr, 0, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	serv_addr.sin_port = htons(*port);

	// 复用套接字的端口	
	if((setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0)
		error_die("setsockopt failed");
	if(bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
		error_die("bind");
	if(*port == 0)
	{
   
		socklen_t serv_size = sizeof(serv_addr);
		if(getsockname(serv_sock, (struct sockaddr*)&serv_addr, &serv_size) < 0)
			error_die("getsockname");
		*port = ntohs(serv_addr.sin_port
  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值