主函数:
-
#include "lcw_shttpd.h"
-
-
//初始化时服务器的默认配置
-
extern struct conf_opts conf_para=
-
{
-
"/usr/local/var/www/cgi-bin/",//CGI根目录
-
"index.html",//默认文件名称
-
"/usr/local/var/www/",//根文件目录
-
"/etc/SHTTPD.conf",//配置文件路径和名称
-
8080, //监听端口
-
4, //最大客户端数量
-
3,//超时时间
-
2//初始化线程数量
-
};
-
struct vec _shttpd_methods[] = {
-
{"GET", 3, METHOD_GET},
-
{"POST", 4, METHOD_POST},
-
{"PUT", 3, METHOD_PUT},
-
{"DELETE", 6, METHOD_DELETE},
-
{"HEAD", 4, METHOD_HEAD},
-
{NULL, 0}
-
};
-
/******************************************************
-
函数名:sig_int(int num)
-
参数:
-
功能:SIGINT信号截取函数
-
*******************************************************/
-
static void sig_int(int num)
-
{
-
Worker_ScheduleStop();
-
return;
-
}
-
/******************************************************
-
函数名:
-
参数:
-
功能:SIGPIPE信号截取函数
-
*******************************************************/
-
static void sig_pipe(int num)
-
{
-
return;
-
}
-
/******************************************************
-
函数名:do_listen()
-
参数:
-
功能:套接字初始化
-
*******************************************************/
-
int do_listen()
-
{
-
struct sockaddr_in server;
-
int ss = -1;
-
int err = -1;
-
int reuse = 1;
-
int ret = -1;
-
// 初始化服务器地址
-
memset(&server, 0, sizeof(server));
-
server.sin_family = AF_INET;
-
server.sin_addr.s_addr=htonl(INADDR_ANY);
-
server.sin_port = htons(conf_para.ListenPort);
-
//信号截取函数
-
signal(SIGINT, sig_int);
-
signal(SIGPIPE, sig_pipe);
-
//生成套接字文件描述符
-
ss = socket (AF_INET, SOCK_STREAM, 0);
-
if (ss == -1)
-
{
-
printf("socket() error\n");
-
ret = -1;
-
goto EXITshttpd_listen;
-
}
-
//设置套接字地址和端口复用
-
err = setsockopt (ss, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
-
if (err == -1)
-
{
-
printf("setsockopt SO_REUSEADDR failed\n");
-
}
-
//绑定IP和套接字描述符
-
err = bind (ss, (struct sockaddr*) &server, sizeof(server));
-
if (err == -1)
-
{
-
printf("bind() error\n");
-
ret = -2;
-
goto EXITshttpd_listen;
-
}
-
//设置服务器侦听队列长度
-
err = listen(ss, conf_para.MaxClient*2);
-
if (err)
-
{
-
printf ("listen() error\n");
-
ret = -3;
-
goto EXITshttpd_listen;
-
}
-
-
ret = ss;
-
EXITshttpd_listen:
-
return ret;
-
}
-
-
int l_main()
-
{
-
int ss = -1;
-
ss = do_listen();
-
return 0;
-
}
-
/******************************************************
-
函数名:main(int argc, char *argv[])
-
参数:
-
功能:主函数
-
*******************************************************/
-
int main(int argc, char *argv[])
-
{
-
signal(SIGINT, sig_int);//挂接信号
-
Para_Init(argc,argv);//参数初始化
-
int s = do_listen();//套接字初始化
-
Worker_ScheduleRun(s);//任务调度
-
return 0;
-
}
头文件:
-
//start from the very beginning,and to create greatness
-
//@author: Chuangwei Lin
-
//@E-mail:979951191@qq.com
-
//@brief: SHTTPD服务器的实现:主要的数据结构
-
//配置文件的结构//
-
#ifndef _LCW_SHTTP_H_
-
#define _LCW_SHTTP_H_
-
#include <stdio.h>
-
#include <getopt.h>//getopt_long()函数所在库函数
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
#include <time.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <sys/socket.h>
-
#include <sys/wait.h>
-
#include <sys/time.h>
-
#include <netinet/in.h> // for sockaddr_in
-
#include <netdb.h> // for hostent
-
#include <pthread.h>
-
#include <arpa/inet.h>
-
#include <signal.h>
-
#include <errno.h> // we want to catch some of these after all
-
#include <unistd.h> // protos for read, write, close, etc
-
#include <dirent.h> // for MAXNAMLEN
-
#include <limits.h>
-
#include <getopt.h>
-
#include <unistd.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
#include <ctype.h>
-
#include <stddef.h>
-
#define big_int_t long
-
#define URI_MAX 16384 // Default max request size
-
//线程的状态值
-
enum
-
{
-
WORKER_INITED,//初始化
-
WORKER_RUNNING,//正在执行
-
WORKER_DETACHING,//正在卸载
-
WORKER_DETACHED,//已经卸载
-
WORKER_IDEL//空闲
-
};
-
struct conf_opts
-
{
-
char CGIRoot[128]; //CGI根目录
-
char DefaultFile[128]; //默认文件名称
-
char DocumentRoot[128]; //根文件目录
-
char ConfigFile[128]; //配置文件路径和名称
-
int ListenPort; //监听端口
-
int MaxClient; //最大客户端数量
-
int TimeOut; //超时时间
-
int InitClient; //初始化线程数量
-
};
-
// HTTP协议的方法
-
typedef enum SHTTPD_METHOD_TYPE{
-
METHOD_GET, //GET方法
-
METHOD_POST, //POST方法
-
METHOD_PUT, //PUT方法
-
METHOD_DELETE, //DELETE方法
-
METHOD_HEAD, //HEAD方法
-
METHOD_CGI, //CGI方法
-
METHOD_NOTSUPPORT
-
}SHTTPD_METHOD_TYPE;
-
-
enum {HDR_DATE, HDR_INT, HDR_STRING};//HTTP头部类型
-
-
typedef struct shttpd_method
-
{
-
SHTTPD_METHOD_TYPE type;
-
int name_index;
-
}shttpd_method;
-
-
typedef struct vec
-
{
-
char* ptr;//字符串
-
int len;//字符串长度
-
SHTTPD_METHOD_TYPE type;//字符串表示类型
-
}vec;
-
-
struct http_header {
-
int len; //Header name length
-
int type; // Header type
-
size_t offset; // Value placeholder
-
char* name; // Header name
-
};
-
-
// This structure tells how HTTP headers must be parsed.
-
// Used by parse_headers() function.
-
#define OFFSET(x) offsetof(struct headers, x)
-
-
union variant {
-
char* v_str;
-
int v_int;
-
big_int_t v_big_int;
-
time_t v_time;
-
void (*v_func)(void);
-
void *v_void;
-
struct vec v_vec;
-
};
-
-
//头部结构
-
struct headers
-
{
-
union variant cl; //内容长度
-
union variant ct; //内容类型
-
union variant connection; //连接状态
-
union variant ims; //最后修改时间
-
union variant user; //用户名称
-
union variant auth; //权限
-
union variant useragent; //用户代理
-
union variant referer; //参考
-
union variant cookie; //Cookie
-
union variant location; //位置
-
union variant range; //范围
-
union variant status; //状态值
-
union variant transenc; //编码类型
-
};
-
-
struct cgi{
-
int iscgi;
-
struct vec bin;
-
struct vec para;
-
};
-
struct worker_ctl;//要先声明
-
struct worker_opts{
-
pthread_t th; //线程的ID号
-
int flags; //线程状态
-
pthread_mutex_t mutex;//线程任务互斥
-
struct worker_ctl *work;//本线程的总控结构
-
};
-
struct worker_conn;//要先声明
-
//请求结构
-
struct conn_request{
-
struct vec req;//请求向量
-
char *head; //请求头部\0'结尾
-
char *uri; //请求URI,'\0'结尾
-
char rpath[URI_MAX];//请求文件的真实地址\0'结尾
-
int method; //请求类型
-
//HTTP的版本信息
-
unsigned long major;//主版本
-
unsigned long minor;//副版本
-
struct headers ch;//头部结构
-
struct worker_conn *conn;//连接结构指针
-
int err;
-
};
-
//响应结构
-
struct conn_response{
-
struct vec res; //响应向量
-
time_t birth_time; //建立时间
-
time_t expire_time;//超时时间
-
int status; //响应状态值
-
int cl; //响应内容长度
-
int fd; //请求文件描述符
-
struct stat fsate; //请求文件状态
-
struct worker_conn *conn;//连接结构指针
-
};
-
struct worker_conn
-
{
-
#define K 1024
-
char dreq[16*K]; //请求缓冲区
-
char dres[16*K]; //响应缓冲区
-
int cs; //客户端套接字文件描述符
-
int to; //客户端无响应时间超时退出时间
-
struct conn_response con_res;
-
struct conn_request con_req;
-
struct worker_ctl *work; //本线程的总控结构
-
};
-
-
struct worker_ctl
-
{
-
struct worker_opts opts;//用于表示线程的状态
-
struct worker_conn conn;//用于表示客户端请求的状态和值
-
};
-
-
//文件内容的类型格式
-
struct mine_type{
-
char* extension;//扩展名
-
int type;//类型
-
int ext_len;//扩展名长度
-
char* mime_type;//内容类型
-
};
-
-
-
void Para_Init(int argc, char *argv[]);
-
int Request_Parse(struct worker_ctl *wctl);
-
int Request_Handle(struct worker_ctl* wctl);
-
-
int Worker_ScheduleRun();
-
int Worker_ScheduleStop();
-
void Method_Do(struct worker_ctl *wctl);
-
void uri_parse(char *src, int len);
-
struct mine_type* Mine_Type(char *uri, int len, struct worker_ctl *wctl);
-
-
-
-
#define DBGPRINT printf
-
#endif
Makefile:
-
CFLAGS = -Wall -g
-
LIBS = -lpthread
-
TARGET = lcw_shttpd
-
RM = rm -f
-
OBJS = lcw_shttpd_parameters.o lcw_shttpd.o lcw_shttpd_worker.o lcw_shttpd_uri.o lcw_shttpd_request.o lcw_shttpd_method.o lcw_shttpd_mine.o lcw_shttpd_error.o
-
all:$(OBJS)
-
gcc -o $(TARGET) $(OBJS) $(LIBS)
-
clean:
-
$(RM) $(TARGET) $(OBJS)
书上的代码其实有很多错误,网上下载的源码好像有些地方也是有点怪怪的。编译可以通过,运行的时候,在浏览器上输入主机IP,有显示访问,dowork,但是默认的html没有运行。因为知识还不是很熟练,所以打算再熟悉下HTTP协议,以及学习另一个web服务器。
阅读(1686) | 评论(0) | 转发(0) |