tinyhttpd linux运行,琐事的学习——tinyhttpd简易WEB服务器

tinyhttpd是一个超轻量型Http Server,使用C语言开发,全部代码只有502行。

我从sourceforge上下载后编译不通过,提示找不到libsocket,发现去掉对libsocket的依赖也没问题

httpd: httpd.c

gcc -g -W -Wall -lsocket -lpthread -o httpd httpd.c

#改为

httpd: httpd.c

gcc -g -W -Wall -lpthread -o httpd httpd.c

执行cgi的函数中也有错误

#273行

execl(path, path, NULL);

#改为

execl(path, query_string, NULL);

编译运行./httpd就可以把web服务运行起来了。

下面学习几段源代码

1,main函数初始化套接口监听并接收连接,针对每个连接开启线程去处理

int main(void)

{

int server_sock = -1;

u_short port = 8080;

int client_sock = -1;

struct sockaddr_in client_name;

int client_name_len = sizeof(client_name);

pthread_t newthread;

server_sock = startup(&port);

printf("httpd running on port %d\n", port);

while (1)

{

client_sock = accept(server_sock,

(struct sockaddr *)&client_name,

&client_name_len);

if (client_sock == -1)

error_die("accept");

/* accept_request(client_sock); */

if (pthread_create(&newthread , NULL, accept_request, client_sock) != 0)

perror("pthread_create");

}

close(server_sock);

return(0);

}

2,accept_request函数解析客户端请求,判断是请求静态文件还是cgi代码(通过请求类型以及参数来判定),如果是静态文件则将文件输出给前端,如果是cgi则进入cgi处理函数

3,execute_cgi函数负责将请求传递给cgi程序处理,服务器与cgi之间通过管道pip通信,首先初始化两个管道,并创建子进程去执行cgi函数

if (pipe(cgi_output) < 0) {

cannot_execute(client);

return;

}

if (pipe(cgi_input) < 0) {

cannot_execute(client);

return;

}

if ( (pid = fork()) < 0 ) {

cannot_execute(client);

return;

}

子进程中,用刚才初始化的管道替换掉标准输入标准输出,将请求参数加到环境变量中,调用execl执行cgi程序获得输出。

if (pid == 0) /* child: CGI script */

{

char meth_env[255];

char query_env[255];

char length_env[255];

dup2(cgi_output[1], 1);

dup2(cgi_input[0], 0);

close(cgi_output[0]);

close(cgi_input[1]);

sprintf(meth_env, "REQUEST_METHOD=%s", method);

putenv(meth_env);

if (strcasecmp(method, "GET") == 0) {

sprintf(query_env, "QUERY_STRING=%s", query_string);

putenv(query_env);

}

else { /* POST */

sprintf(length_env, "CONTENT_LENGTH=%d", content_length);

putenv(length_env);

}

execl(path, query_string, NULL);

exit(0);

}

服务器"线程"继续将post的请求头发送给子进程(cgi程序),然后获取cgi程序的标准输出作为响应内容发送给客户端。

else { /* parent */

close(cgi_output[1]);

close(cgi_input[0]);

if (strcasecmp(method, "POST") == 0)

for (i = 0; i < content_length; i++) {

recv(client, &c, 1, 0);

write(cgi_input[1], &c, 1);

}

while (read(cgi_output[0], &c, 1) > 0)

send(client, &c, 1, 0);

close(cgi_output[0]);

close(cgi_input[1]);

waitpid(pid, &status, 0);

}

502行代码都比较精炼,服务器在完成一些web功能外还处理了一些异常情况,500状态码cgi执行出错,404找不到文件错误之类的,开始以为putenv函数会设置个全局变量,当多用户访问的时候会互相影响,后来测试了一下发现设置的变量是互相隔离的,这些代码值得学习。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值