TinyHTTPd forWindows
前言
TinyHTTPd是一个开源的简易学习型的HTTP服务器,项目主页在:.NET/,源代码下载:https://sourceforge.Net/projects/tinyhttpd/,因为是学习型的代码,已经有好多年没更新了,也没什么更新必要,整个代码才500多行,10多个函数,对于学习HTTP服务器的原理来说非常有帮助,,把代码读一遍,再按照执行处理流程调试一下,基本上可以搞清楚Web服务器在收到静态页面请求和CGI请求的一些基本处理逻辑。源代码的注释我这里就不讲了,本身代码比较简单,而且网上这样的文章汗牛充栋,可以去后面的参考文档阅读下。
本文主要是将TinyHTTPd进行一些简单移植,使其可以在Windows上面运行调试,让只有Windows开发调试环境的小伙伴也能够学习学习。
修改明细
支持Windows部分
1、 Windows下的socket支持(微小改动,变量,宏调整等等)。
2、 接入基于Windows平台的一个微型线程池库(项目在用),对于每个新的http请求抛到线程池处理,源代码使用的是基于Linux的pthread。
3、 部分字符串比较函数修改为windows平台的对应支持函数,以及其它一些相应兼容性修改。
4、 CGI部分支持了Python脚本和Windows批处理脚本,其它的如果需要支持可以进行修改,另外,CGI部分目前实现比较粗糙,完全是为了体现一下CGI请求的原理(POST的CGI处理仅仅是把提交的数据返回给客户端显示)。
5、 CGI部分使用了匿名管道,匿名管道不支持异步读写数据,因此需要控制读写匿名管道的次数(建议仅读一次,并且CGI的返回字符长度不要超过2048字节)。
优化
1、 给客户端返回数据时,合并了需要发送的数据,使用send一次发送,而不是每次发送几个字符,不过这里没有进行send失败的错误处理,学习代码吧,如果是商用代码,send失败是需要重试的(当然,商用代码一般都是使用异步socket),这个地方之前作者分成多次发送的目的可能是为了体现网络数据传输的原理。
2、 合并了一些公用代码。
3、 代码里面直接写死了绑定80端口,如果需要由系统自动分配端口就把这句代码:u_short port = 80修改为u_short port = 0,绑死80端口是为了使用浏览器测试时比较方便。
bug修改
1、 cat函数里面使用fgets读取文件进行数据发送时,有可能发送不完整。
资源补充
1、 补充批处理的cgi支持和py脚本的cgi支持(都比较简单,需要注意的是py脚本支持需要本地安装python2.x的环境)。
测试情况
主页
URL:
其它静态页面
URL:
Python CGI
URL:?p.py
批处理 CGI
URL:?p.bat
POST CGI
URL:
源代码
本来不想帖代码的,还是贴一点吧,工程下载请点这里。
[cpp]
/* -------------------------------------------------------------------------
// 文件名 : tinyhttp.cpp
// 创建者 : magictong
// 创建时间 : 2016/11/16 17:13:55
// 功能描述 : support windows of tinyhttpd, use mutilthread...
//
// $Id: $
// -----------------------------------------------------------------------*/
/* J. David‘s webserver */
/* This is a simple webserver.
* Created November 1999 by J. David Blackstone.
* CSE 4344 (Network concepts), Prof. Zeigler
* University of Texas at Arlington
*/
/* This program compiles for Sparc Solaris 2.6.
* To compile for Linux:
* 1) Comment out the #include <pthread.h> line.
* 2) Comment out the line that defines the variable newthread.
* 3) Comment out the two lines that run pthread_create().
* 4) Uncomment the line that runs accept_request().
* 5) Remove -lsocket from the Makefile.
*/
#include "stdafx.h"
#include "windowcgi.h"
#include "ThreadProc.h"
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <WinSock2.h>
#pragma comment(lib, "wsock32.lib")
#pragma warning(disable : 4267)
#define ISspace(x) isspace((int)(x))
#define SERVER_STRING "Server: tinyhttp /0.1.0\r\n"
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// 类名 : CTinyHttp
// 功能 :
// 附注 :
// -------------------------------------------------------------------------
class CTinyHttp
{
public:
typedef struct tagSocketContext
{
SOCKET socket_Client;
tagSocketContext() : socket_Client(-1) {}
} SOCKET_CONTEXT, *PSOCKET_CONTEXT;
/**********************************************************************/
/* A request has caused a call to accept() on the server port to
* return. Process the request appropriately.
* Parameters: the socket connected to the client */
/**********************************************************************/
void accept_request(nilstruct&, SOCKET_CONTEXT& socket_context)
{
printf("Tid[%u] accept_request\n", (unsigned int)::GetCurrentThreadId());
#ifdef _DEBUG
// 测试是否可以并发
::Sleep(200);
#endif
char buf[1024] = {0};
int numchars = 0;
char method[255] = {0};
char url[255] = {0};
char path[512] = {0};
int i = 0, j = 0;
struct stat st;