xinetd的安装配置以及xhttpd应用程序的实现

借助xinetd可以实现一个简单的Web服务器,框架如下图所示

å¨è¿éæå¥å¾çæè¿°

 

1.安装xinetd

sudo yum install xinetd

2.配置
举例:xinetd接收到客户端请求后,启动xhttpd的可执行文件,(xhttpd服务器的代码需要自己编写,用于处理/回应请求)

(1)在/etc/xinetd.d/下创建一个名为 xhttpd 的配置文件
注意:等号两边有1个空格,要想补齐必须使用Tab键

service xhttpd
{
	socket_type=stream
	protocol=tcp
	wait=no
	user=nobody
	server=/usr/local/sbin/httpd/xhttpd  # xhttpd是可执行文件,放在/usr/local/sbin/httpd目录下
	/server_args=/var/xhttp/mh_html # 浏览器请求的资源所在的目录
	disable=no
	flags=IPv4
}

(2)vi /etc/services 添加端口

xhttpd 9523/tcp   # xhttpd server
xhttpd 9523/udp

(3)重启xinetd服务器sudo service xinetd restart

(4)查看xinetd是否启动成功:ps aux | grep xinetd

root      15607  0.2  0.0  27164  1032 ?        Ss   10:24   0:00 /usr/sbin/xinetd -stayalive -pidfile /var/run/xinetd.pid
gjw       15619  0.0  0.0 112724   988 pts/0    S+   10:24   0:00 grep --color=auto xinetd

 

 

先看xhttpd的主函数

首先xinetd进程拉起xhttpd 传入参数argv[1]表示资源文件所在的目录

首先需要将工作目录切换到资源目录。

读取http 请求行

拆分http 请求行

然后判断是否符合要求

这里用stat 

stat函数讲解

表头文件:    #include <sys/stat.h>
             #include <unistd.h>
定义函数:    int stat(const char *file_name, struct stat *buf);
函数说明:    通过文件名filename获取文件信息,并保存在buf所指的结构体stat中
返回值:      执行成功则返回0,失败返回-1,错误代码存于errno

 

判断文件是否是目录,作目录的处理

如果是文件,作文件的处理

需要注意,这里xinetd通过输出重定向了,所以在xhttpd中只需要输出到标准输出即可

//xinetd ---> xhttpd argv[1]:浏览器请求的资源所在的目录/server_args=/var/xhttp/mh_html 
int main(int argc,const char* argv[])
{
    if(argc < 2)
        send_error(500,"server error : argc < 2");
    if(chdir(argv[1]) < 0)
        send_error(500,"server error : chdir error");
 
    char line[LEN],type[LEN],path[LEN],protocol[LEN];
	
	//读取浏览器发来的请求,即:GET /lufei.jpg HTTP/1.1
    if(fgets(line,sizeof(line),stdin) == NULL) //标准输入 ---> line
        send_error(500,"server error : type path protocol");
    if(sscanf(line,"%[^ ] %[^ ] %[^ ]",type,path,protocol) != 3) //line ---> type,path,protocol
        send_error(400,"bad request");
		
    if(strcasecmp(type,"GET") != 0) //type = GET
        send_error(400,"method not allow");
    if(path[0] != '/') // path = /lufei.jpg
        send_error(404,"file not found");
 
    while(fgets(line,sizeof(line),stdin) != NULL)
    {
        if(strcmp(line,"\n") == 0 || strcmp(line,"\r\n") == 0)
            break;
    }
 
    char file[LEN];
    struct stat st;
    file[0] = '.';
    decode(file+1,path);
    //printf("%s\n",&path[1]);
    //printf("%s\n",file);
    if(stat(file,&st) < 0)
    {
        printf("file : %s\r\n",file);
        send_error(500,"server error : stat");
    }
    if(S_ISDIR(st.st_mode))
    {
        send_header(200,"OK","text/html;charset=utf-8");
        printf("<html>"
                    "<head><title>Index of %s</title></head>"
                    "<body bgcolor=\"#cc99cc\">"
                        "<h4>Index of %s</h4>"
                        "<pre>"
                    ,file,file);
        struct dirent** dl;
        int nf = scandir(file,&dl,NULL,alphasort);
        if(nf < 0)
            perror("scandir");
        else
        {
            struct stat fst;
            char stfile[LEN];
            for(int i=0;i<nf; ++i)
            {
                strcpy(stfile,file);
                strcat(stfile,"/");
                strcat(stfile,dl[i]->d_name);
                if(lstat(stfile,&fst) < 0)
                    printf("<a href=\"%s%s/\">%-32.32s/</a>",file+1,dl[i]->d_name,dl[i]->d_name);
                else if(S_ISDIR(fst.st_mode))
                    printf("<a href=\"%s%s/\">%-32.32s/</a> \t\t%14lld",file+1,dl[i]->d_name,dl[i]->d_name,(long long)fst.st_size);
                else
                    printf("<a href=\"%s%s\">%-32.32s</a> \t\t%14lld",file+1,dl[i]->d_name,dl[i]->d_name,(long long)fst.st_size);
                printf("<br/>");
            }
        }
        printf("</pre>"
               "</body>"
               "</html>");
    }
    else
    {
    //普通文件
    FILE* fp = fopen(file,"r");
    if(fp == NULL)
        send_error(500,"server error : open file");
    send_header(200,"send header",get_filetype(file));
    int ch;//这里必须用int判断EOF,我真是菜鸡。
    while((ch = getc(fp)) != EOF)
    {
        putchar(ch);
    }
    fflush(stdout);
    fclose(fp);
    fp = NULL;
    }
//  printf("test success !\n");
 
    return 0;
}

这里有一些编码问题,比较复杂,暂时不用管。

来看看发送响应头函数

void send_header(int status, char* title, char* filetype)
{
    if(title == NULL || filetype == NULL)
    {
        title = "ERROR";
        filetype = "text/plain; charset=utf-8";
    }
    printf("HTTP/1.1 %d %s\r\n",status,title);
    printf("Content-Type:%s\r\n",filetype);
    printf("\r\n");
}

 

void send_error(int status,char* title)
{
    if(title == NULL)
        title = "ERROR";
    send_header(status,title,"text/html; charset=utf-8");
	
	//将html的内容直接printf,就是回复给浏览器
    printf("<html>\n"
                "<head><title>%d %s</title></head>\n"
                "<body bgcolor=\"#cc99cc\">\n"
                    "<h4>error!</h4>\n"
                    "<hr>\n"
                    "<address>\n"
                        "<a href=\"http://blog.csdn.net/gongluck93/\">gongluck</a>\n"
                    "</address>\n"
                "</body>\n"
            "</html>",
           status,title);
		   
    fflush(stdout); //刷新标准输出缓冲区,让浏览器显示页面
    exit(1);
}

判断文件类型

char* get_filetype(const char* file)
{
    if(file == NULL)
        return NULL;
    char* dot = strrchr(file,'.');
    if(*dot == '\0')
        return "text/plain; charset=utf-8";
    else if(strcmp(dot,".html") == 0)
        return "text/html; charset=utf-8";
    else if(strcmp(dot, ".jpg") == 0)
        return "image/jpeg";
    else if(strcmp(dot, ".gif") == 0)
        return "image/gif";
    else if(strcmp(dot, ".png") == 0)
        return "image/png";
    else if(strcmp(dot, ".wav") == 0)
        return "audio/wav";
    else if(strcmp(dot, ".avi") == 0)
        return "video/x-msvideo";
    else if(strcmp(dot, ".mov") == 0)
        return "video/quicktime";
    else if(strcmp(dot, ".mp3") == 0)
        return "audio/mpeg";
    else
        return "text/plain; charset=utf-8";
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值