您的位置:首页 > 理论基础 > 计算机网络

用C编写一个简单的、基本的http服务器

2014-09-20 01:33 225 查看
翻到一份去年自己实现的http服务器,编译环境为VC6.0,用纯C编写,本来想完善以后才发出来的,结果拖延症发作......

ps:代码仅供学习

工程下载:http://download.csdn.net/detail/wailovet/7945827

main.h

________________________

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

#include <winsock2.h>
#include <windows.h>		   //包含文件
#pragma comment(lib, "ws2_32.lib") //静态编译

#define CONFIG_FILE "./config"
#define MAXDATA 512

typedef struct {
char url[256];
char dir[256];
char host[256];
char accept[256];
char accept_language[64];
char content_type[64];
char cookie[256];
} RequestHeaders ;

struct {
char root_path[256];
char default_file[64];
int server_port;
} Config ;

DWORD WINAPI Thread(LPVOID lpParam);//等待连接进程

//功能   将接收到的http头信息解析到结构RequestHeaders
//参数   RequestHeaders为接受http请求头信息,str为字符串形式的头信息,socket为当前连接客户字符串
//返回值 0为正常,1为出现异常
int strToRequestHeaders(RequestHeaders *rh,char *str,int socket);

//功能   根据http请求信息发送指定文件
//参数   socket为当前连接客户字符串,RequestHeaders为接受http请求头信息
//返回值 0为正常发送,-1为文件打开失败
int sendFile(int socket,RequestHeaders rh);

//功能   加载http服务器配置
void loadConfig();

//功能   服务端http头信息的串接
//参数   RequestHeaders为接受http请求头信息
//返回值 服务端http头信息字符串形式
char* makeHeadPack(RequestHeaders rh);

char* readLoad(char *allConfig,char *name);

//功能   查询文件大小
//参数   fp为路径字符串
//返回值 文件大小,单位为字节
long getFileSize(char* fp);

//功能   当前连接的用户跳转到指定连接
//参数   socket为当前连接客户字符串
//返回值 为0
int moveUrl(int socket,char *url);

//功能   判断路径是否为文件夹
//参数   fp为路径字符串
//返回值 1为参数所指定路径为文件夹 0为普通文件
int isFolder(char* fp);


main.c

________________________________________________

#include "main.h"

struct sockaddr_in my_socket_info;//服务端配置
int my_first_socket,tmp_socket;
int backlog = 5;
int pnum = 0; //线程数

int main(){

WSADATA WSAData={0};
WSAStartup(MAKEWORD(2,2), &WSAData);
loadConfig();
my_socket_info.sin_family = PF_INET;
my_socket_info.sin_port = htons(Config.server_port);
my_socket_info.sin_addr.s_addr = htonl(INADDR_ANY);
my_first_socket = socket(PF_INET, SOCK_STREAM, 0);
bind(my_first_socket,(struct sockaddr *)&my_socket_info,sizeof(my_socket_info));
listen(my_first_socket,backlog);
while(1){
tmp_socket = accept(my_first_socket,(struct sockaddr *)&my_socket_info,NULL);
CreateThread(NULL,0,Thread,NULL,0,NULL);
//printf("starts");
Sleep(50);
}
return 0;
}

DWORD WINAPI Thread( LPVOID lpParam )
{
char head_buf[2*MAXDATA]="";
char buf[MAXDATA+1]="";//数据缓冲区
int my_sec_socket;
RequestHeaders head_info;
int i = 0,q=0;

my_sec_socket = tmp_socket;
pnum++;

//接收http头信息
while((i = recv(my_sec_socket,buf,MAXDATA,0))){
buf[i] = '\0';
strcat(head_buf,buf);
q=q+i;
if(i<MAXDATA){
break ;
}
}

// 解析头信息
if(strToRequestHeaders(&head_info,head_buf,my_sec_socket)==1){
closesocket(my_sec_socket);
return 0;
}

strcpy(head_buf,makeHeadPack(head_info));
send(my_sec_socket,head_buf, strlen(head_buf), 0);
sendFile(my_sec_socket,head_info);
pnum--;
closesocket(my_sec_socket);
return 0;
}

int strToRequestHeaders(RequestHeaders *rh,char *str,int socket)
{

char tmp[2048];
char *s;
strcpy(tmp,str);

s = strstr(strupr(tmp) ,"GET ")+4;
if(!(s-4)){
return 1;
}
strstr(s," ")[0]='\0';
strcpy(rh->dir,Config.root_path);
strcat(rh->dir,s);
if(rh->dir[strlen(rh->dir)-1]=='/'){
strcat(rh->dir,Config.default_file);
}

if(isFolder(rh->dir)){
strcat(s,"/");
moveUrl(socket,s);
return 1;
}
if(strrchr(rh->dir,'.')){
strcpy(rh->content_type,strrchr(rh->dir,'.'));
}
return 0;
}

int sendFile(int socket,RequestHeaders rh)
{
unsigned char buf[MAXDATA];
char *error = "";
int i=MAXDATA,sum=0;
FILE * fp = fopen(rh.dir,"rb");
if(NULL == fp){
send(socket,"404", 3, 0);
return -1; //打开错误
}
while( (i = fread(buf,sizeof(unsigned char), MAXDATA,fp)) != 0 ){
send(socket,buf,i, 0);
}
fclose(fp);
return 0;
}

/*
bug未解决

int sendFile(int socket,RequestHeaders rh)
{
unsigned char buf[MAXDATA];
char *error = "";
int i=MAXDATA,sum=0;
int fp = open(rh.dir,O_RDONLY);
printf("%s",rh.dir);
if(!fp){
send(socket,"404", 3, 0);
return -1; //打开错误
}

while( !eof(fp) ){
i = read(fp,buf,MAXDATA);
send(socket,buf,i, 0);
}
close(fp);
return 0;
}*/
char* makeHeadPack(RequestHeaders rh)
{
char header_buf[256]="HTTP/1.1 200 OK\r\n";
char str_file_size[25];
if(strstr(rh.content_type,"html")){
strcat(header_buf,"Content-Type: text/html;\r\n");
}

itoa(getFileSize(rh.dir), str_file_size, 10);
strcat(header_buf,"Content-Length:");
strcat(header_buf,str_file_size);
strcat(header_buf,"\r\nServer: tinyHttpServer\r\nConnection: close\r\n\r\n");
return header_buf;

}

long getFileSize(char* fp)
{
struct stat f_stat;
if(isFolder(fp)){
return -1;
}
stat(fp, &f_stat);
return f_stat.st_size;
}

char *readLoad(char *allConfig,char *name){
char line[256],*tmp;
int i,k;
tmp = strstr(allConfig,name);
k=0;
if(!tmp){
return "";
}
//这里需要删除空格字符
for(i=0;tmp[k]!='\0'&&tmp[k]!='\n';k++){
if(tmp[k]!=' '&&tmp[k]!='\n'&&tmp[k]!=13){
line[i]=tmp[k];
i++;
}
}
line[i]='\0';
strcpy(line,strstr(line,":")+1);
return line;
}
void loadConfig()
{
char ch[2];
char *line;
char *conf;
int i;
FILE * fp = fopen(CONFIG_FILE,"rb");
if(!fp){
printf("error");
return ;
}
ch[1] = '\0';
conf = malloc(sizeof(char)*getFileSize(CONFIG_FILE)+4);
conf[0]= '\0';
while((ch[0]=fgetc(fp))!=EOF){
strcat(conf,ch)	;
}

strcpy(Config.root_path,readLoad(conf,"root_path"));
Config.server_port = atoi(readLoad(conf,"port"));
strcpy(Config.default_file,readLoad(conf,"default_page"));

printf(" %s \n %d",Config.default_file,Config.server_port);

}

int moveUrl(int socket,char *url)
{
char head[512];
strcpy(head,"HTTP/1.1 302 Found\r\nServer: tinyHttpServer\r\nLocation:");
strcat(head,url);
strcat(head,"\r\n\r\n");
send(socket,head, strlen(head), 0);
return 0;
}

int isFolder(char* fp)
{

char*  root_dir = _getcwd(NULL,NULL);
if(_chdir(fp)==0){
_chdir(root_dir);
return 1;
}
_chdir(root_dir);
return 0;
}


config

————————————————————

root_path : ./www
port : 51000
default_page:index.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: