利用xinetd实现简单web服务器(镜像站)

本文介绍如何使用xinetd搭建一个简易的HTTP服务器,并提供了一个基于C语言实现的HTTP服务器示例代码。该服务器能处理基本的GET请求,展示目录内容及发送普通文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

浏览效果:

linux服务器安装xinetd后,在/etc/xinetd.d/目录下创建xhttpd文件,并输入内容:

service xhttpd
{
    socket_type = stream
    protocol = tcp
    wait = no
    user = gongluck
    server = /home/gongluck/桌面/xhttpd
    server_args = /home/gongluck/桌面/xhttpdir
    disable = no
    flags = IPv4
}
然后在/etc/services文件的最后添加自己使用的端口和进程的名字:

xhttpd      9527/tcp        # xhttpd service
xhttpd      9527/udp        # xhttpd servic
重启服务:

sudo service xinetd restart
xhttpd程序的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#include <dirent.h>

#define LEN 4096

char* get_filetype(const char* file);
void send_error(int status,char* title);
void send_header(int status,char* title, char* filetype);
void decode(char* to, char* from);
void encode(char* to, char* from);

int main(int argc,const char* argv[])
{
    if(argc < 2)
        send_error(500,"server error : argc < 2");

    //if(access(argv[1],R_OK | F_OK) != 0)
    if(chdir(argv[1]) < 0)
        send_error(500,"server error : chdir error");

    char line[LEN],type[LEN],path[LEN],protocol[LEN];
    if(fgets(line,sizeof(line),stdin) == NULL)
        send_error(500,"server error : type path protocol");
    if(sscanf(line,"%[^ ] %[^ ] %[^ ]",type,path,protocol) != 3)
        send_error(400,"bad request");
    if(strcasecmp(type,"GET") != 0)
        send_error(400,"method not allow");
    if(path[0] != '/')
        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;
}

int hex2d(char hex)
{
    if(hex >= '0' && hex <= '9')
        return hex-'0';
    else if(hex >= 'a' && hex <= 'f')
        return hex-'a'+10;
    else if(hex >= 'A' && hex <= 'F')
        return hex-'A'+10;
    else
        return hex;
}

void decode(char* to, char* from)
{
    if(to == NULL || from == NULL)
        return;

    while(*from != '\0')
    {
        if(from[0] == '%' && isxdigit(from[1]) && isxdigit(from[2]))
        {
            *to = hex2d(from[1])*16 + hex2d(from[2]);
            from += 3;
        }
        else
        {
            *to = *from;
            ++from;
        }
        ++to;
    }
    *to = '\0';
}

void encode(char* to, char* from)
{
    if(to == NULL && from == NULL)
        return;

    while(*from != '\0')
    {
        if(isalnum(*from) || strchr("/._-~",*from) != NULL)
        {
            *to = *from;
            ++to;
            ++from;
        }
        else
        {
            sprintf(to,"%%%02x",*from);
            to += 3;
            from += 3;
        }
    }
    *to = '\0';
}

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";
}

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");
    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.youkuaiyun.com/gongluck93/\">gongluck</a>\n"
                    "</address>\n"
                "</body>\n"
            "</html>",
           status,title);
    fflush(stdout);
    exit(1);
}
由于xinetd会帮助我们与浏览器建立好连接,并且将stdin重定向到浏览器的发送端,stdout重定向到浏览器的接收端。所以xhttpd程序只需要从标准输入中读取浏览器的请求数据,把响应数据写入标准输出中即可。

这里只是用http协议的很简单的一部分:

GET /请求的文件名 HTTP/1.1
HTTP/1.1 状态码 描述
Content-Type:回传文件类型
\r\n
回传文件数据

<think>好的,我现在需要帮助用户在Kylin V10 SP3系统上通过Yum源安装xinetd服务。首先,我得确认用户的环境和需求。用户提到的是Kylin Server V10 SP3,可能基于ARM64或LoongArch64架构,但安装xinetd的步骤应该类似,只是Yum源配置可能不同。 首先,xinetd是一个增强型的网络服务守护进程,用于管理其他网络服务。在较新的Linux发行版中,有些服务可能默认使用systemd,但某些旧服务或特定场景下仍需xinetd。用户可能是在配置PXE无人值守安装时需要用到xinetd,如参考引用中提到的构建PXE服务器步骤,其中重启了xinetd服务[^2]。 接下来,安装xinetd通常通过Yum包管理器。但需要确保Yum源已正确配置。麒麟系统可能使用自己的软件源,用户需要先确认Yum源是否可用。如果用户遇到无法找到xinetd包的情况,可能需要检查源是否启用或是否有网络访问权限。 步骤可能包括: 1. 更新Yum缓存,确保获取最新的软件包列表。 2. 使用yum install命令安装xinetd。 3. 安装完成后启用并启动服务,设置开机自启。 但需要特别注意,麒麟系统的软件源名称可能与CentOS或Ubuntu不同,可能存在包名称差异。例如,xinetd包是否存在于默认源中,或者是否需要启用额外的仓库。比如参考引用[3]中提到了复制镜像内容到HTTP目录,可能用户已经配置了本地镜像作为Yum源,这需要检查/etc/yum.repos.d/下的配置文件是否正确指向本地路径或网络源。 如果用户遇到找不到xinetd的情况,可能需要手动添加EPEL或其他第三方源,但需确保兼容性。或者,检查安装介质中是否包含xinetd的rpm包,直接使用rpm安装。例如,参考引用[3]中的操作是将ISO镜像挂载并复制文件到Web目录,可能用户有本地源,可以配置Yum指向该本地路径,然后安装xinetd。 因此,具体步骤可能为: - 确认Yum源配置正确,能够访问包含xinetd的仓库。 - 执行安装命令。 - 验证安装并启动服务。 需要提醒用户注意权限问题,使用sudo或以root用户执行命令。同时,检查防火墙设置,确保服务端口开放,如果xinetd需要对外提供服务的话。</think>在 Kylin V10 SP3 系统中通过 Yum 源安装 `xinetd` 服务的步骤如下: --- ### **1. 更新 Yum 软件包缓存** 确保软件源信息最新: ```bash sudo yum clean all && sudo yum makecache ``` --- ### **2. 安装 xinetd** 直接通过 Yum 安装: ```bash sudo yum install -y xinetd ``` 若提示找不到软件包,需检查以下情况: - **本地镜像源配置**:参考引用[3],若已挂载麒麟系统 ISO 镜像并配置本地 Yum 源,需确认 `/etc/yum.repos.d/` 中的仓库文件正确指向镜像路径[^3]。 - **网络源配置**:若使用网络源,需确保 `/etc/yum.repos.d/kylin.repo` 文件中的 `baseurl` 地址有效。 --- ### **3. 启动服务并设置开机自启** ```bash sudo systemctl start xinetd # 启动服务 sudo systemctl enable xinetd # 启用开机自启 sudo systemctl status xinetd # 验证服务状态 ``` --- ### **4. 验证安装** 检查版本信息: ```bash rpm -qa | grep xinetd ``` 预期输出类似:`xinetd-2.3.15-xxx`。 --- ### **常见问题** 1. **软件包不存在** 若 Yum 源未包含 `xinetd`,需手动下载 RPM 包安装: ```bash wget [xinetd RPM 包 URL] # 从麒麟官方或兼容仓库获取 sudo rpm -ivh xinetd-*.rpm ``` 2. **依赖冲突** 使用 `--nodeps` 强制安装(谨慎操作): ```bash sudo rpm -ivh --nodeps xinetd-*.rpm ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值