一个小型的web server (500行)

#ifndef _MY_UTILS_H_INCLUDE_
#define _MY_UTILS_H_INCLUDE_


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <signal.h>


#define SERVER_PORT			8000
#define BUF_SIZE			1024
#define EPOLL_SIZE			1000
#define METHOD_GET			0
#define METHOD_HEAD			1
#define METHOD_UNSUPPORTED		-1
#define SERVER_NAME			"myserver/0.1"

#define DEFAULT_TYPE			"text/plain"

#define oops(msg)			{perror(msg);exit(0);}

typedef struct file_info_s	file_info_t;

struct file_info_s {
    char		*file_name;
    char		*full_path;
    file_info_t		*next;
    
    char		*content;
    size_t		 content_length;
    char		*content_type;
};



#endif






#include "my_utils.h"




static int handle_connection(int fd);
static void help();
static void sigcatch(int signal);
static int send_message(int fd,char*buffer,size_t len);


static int get_method(char*message);
static file_info_t	*get_file(char*message);

file_info_t	*files=NULL;
static char*msg404="Not found\r\n\r\n";

int main(int ac,char**av)
{
    
    int					 client_fd,listen_fd,epoll_fd;
    char				*full_path=NULL,*dir_name=NULL;
    DIR					*dir=NULL;
    struct dirent			*cur_file=NULL;
    struct stat				 cur_stat;
    struct sockaddr_in			 server_addr,client_addr;
    struct epoll_event			 ev,events[EPOLL_SIZE];
    u_int				 i,events_count=0;
    file_info_t				*cur_file_info=NULL,*last_file_info=NULL;
    socklen_t				 client_addr_len;

    if(ac!=2){
	help();
	exit(0);
    }
    dir_name=av[ac-1];
    if((dir=opendir(dir_name))==NULL){
	printf("Invalid directory -%s.\n",dir_name);
	oops("opendir");
    }
    while((cur_file=readdir(dir))!=NULL){
	full_path=malloc(strlen(cur_file->d_name)+strlen(dir_name)+4);
	sprintf(full_path,"%s%s",dir_name,cur_file->d_name);
	lstat(full_path,&cur_stat);

	if(S_ISREG(cur_stat.st_mode)&&(cur_file->d_name[0]!='.')){
	    if(files==NULL){
		files=malloc(sizeof(file_info_t)+2);
		cur_file_info=files;
	    }else{
		cur_file_info=malloc(sizeof(file_info_t)+2);
	    }
	    cur_file_info->file_name=malloc(strlen(cur_file->d_name)+2);
	    strcpy(cur_file_info->file_name,cur_file->d_name);
	    cur_file_info->full_path=full_path;
	    cur_file_info->next=NULL;
	    cur_file_info->content=NULL;

	    if(last_file_info==NULL)
		last_file_info=cur_file_info;
	    else{
		last_file_info->next=cur_file_info;
		last_file_info=cur_file_info;
		
	    }
	}else{
	    free(full_path);
	}
    }

    (void)signal(SIGINT,sigcatch);
    (void)signal(SIGTERM,sigcatch);


    listen_fd=socket(AF_INET,SOCK_STREAM,0);
    if(listen_fd<0)
	oops("Socket");

    bzero(&server_addr,sizeof(server_addr));
    server_addr.sin_family=AF_INET;
    server_addr.sin_port=htons(SERVER_PORT);
    server_addr.sin_addr.s_addr=INADDR_ANY;

    if(bind(listen_fd,(struct sockaddr*)&server_addr,sizeof(server_addr))<0)
	oops("bind");
    if(listen(listen_fd,5)<0)
	oops("listen");

    epoll_fd=epoll_create(EPOLL_SIZE);
    if(epoll_fd<0)
	oops("epoll_create");
    ev.events=EPOLLIN;
    ev.data.fd=listen_fd;
    if(epoll_ctl(epoll_fd,EPOLL_CTL_ADD,listen_fd,&ev)<0)
	oops("epoll_ctl");

    for(;;){
	events_count=epoll_wait(epoll_fd,events,EPOLL_SIZE,-1);
	if(events_count<0)
	    oops("epoll_wait");
	for(i=0;i<events_count;i++){
	    if(events[i].data.fd==listen_fd){
		client_addr_len=sizeof(struct sockaddr_in);
		client_fd=accept(listen_fd,(struct sockaddr*)&client_addr,&client_addr_len);
		if(client_fd<0)
		    oops("accept");
		ev.data.fd=client_fd;
		if(epoll_ctl(epoll_fd,EPOLL_CTL_ADD,client_fd,&ev)<0)
		    oops("epoll_ctl");
	    }else{ 
		if(handle_connection(events[i].data.fd)<0)
		    oops("handle_connection");
	    }
	}
    }
    close(listen_fd);
    return 0;
}

	    	
static int 
handle_connection(int fd)
{
    int					rc,i,file_fd,method;
    char				message[BUF_SIZE],outb[BUF_SIZE];
    char			       *out;
    struct stat				cur_stat;
    file_info_t			       *file;


    rc=recv(fd,message,BUF_SIZE,0);
    if(rc<0){
	printf("recv wrong");
	close(fd);
	return -1;
    }
    for(i=0;i<rc;i++){
	if(message[i]=='\n'||message[i]=='\r')
	    break;
    }

    if(i>rc-2){
	printf("Invalid request 1\n");
	close(fd);
	return -1;
    }

    message[i]='\0';//cut  

    method=get_method(message);
    if(method==METHOD_UNSUPPORTED){
	printf("Invalid request 2\n");
	close(fd);
	return -1;
    }
    file=get_file(message);
    if(file==NULL){
	out="HTTP/1.1 404 Not Found\r\n";
	if(send_message(fd,out,strlen(out))<0)
	    return -1;
	out="Content-Type:text/html\r\n";
	if(send_message(fd,out,strlen(out))<0)
	    return -1;
	sprintf(outb,"Server:%s\r\nContent-Length:%d\r\n\r\n",
		SERVER_NAME,strlen(msg404));
	if(send_message(fd,outb,strlen(outb))<0)
	    return -1;
	close(fd);
	return 1;
    }
    out="HTTP/1.1 200 OK\r\n";
    if(send_message(fd,out,strlen(out))<0)
	return -1;
    if(file->file_name!=NULL){
	lstat(file->full_path,&cur_stat);
	sprintf(outb,"Content-Lenght:%d\r\nServer:%s\r\n\r\n",
		cur_stat.st_size,SERVER_NAME);
	if(send_message(fd,outb,strlen(outb))<0)
	    return -1;
	if(method==METHOD_GET){
	    file_fd=open(file->full_path,O_RDONLY);
	    if(file_fd==-1){
		printf("Couldn't open %s\n",file->full_path);
		close(fd);
		return -1;
	    }
	    sendfile(fd,file_fd,0,cur_stat.st_size);
	    close(file_fd);
	}else if(method==METHOD_HEAD)
	    return 1;
    }
    close(fd);
}
	

	
	



    








static void 
sigcatch(int signal)
{
    printf("Signal Caugth ,exiting...\n");
    exit(0);
}

static void help()
{
     printf("usage:./main dirname\n");
}
static int send_message(int fd,char*buffer,size_t len)
{
    int rc;
    rc=send(fd,buffer,len,0);
    if(rc<0){
	printf("send error\n");
	close(fd);
	return -1;
    }
    return rc;
}

static int 
get_method(char*req)
{
    if(strncasecmp(req,"GET",3)==0)
	return METHOD_GET;
    if(strncasecmp(req,"HEAD",4)==0)
	return METHOD_HEAD;
    return METHOD_UNSUPPORTED;
}
static file_info_t*
get_file(char*req)
{
    file_info_t				*file_found=NULL;
    char				*uri=NULL;
    u_int				 i;

    if(files==NULL)
	return NULL;
    for(i=0;i<strlen(req);i++){
	if(req[i]==' '){
	    if(uri==NULL)
		uri=req+i+1;
	    else
		break;
	}
    }
    if(i>=strlen(req)){
	return NULL;
    }
    req[i]='\0'; //cut again;

    if(strcmp(uri,"/")==0){
	uri="/index.html";
    }
    if(uri[0]=='/') 
	uri++;
    file_found=files;
    while(1){
	if(strcasecmp(uri,file_found->file_name)==0)
	    return file_found;
	if(file_found->next==NULL)
	    return NULL;
	file_found=file_found->next;
    }
    return NULL;
}













obj=my_server.o 
main=main
$(main):$(obj)
	gcc -g -o $(main) $(obj)
my_server.o:
	gcc -g -c my_server.c
clean:
	rm -rf $(main) $(obj)
	



开启server :./main  dir_name


访问:curl http://locahost:8000/test.txt                       (test.txt是你指定的目录dir_name下面的一个常规文件)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值