c语言编写http服务器(Linux下运行)

news2024/9/25 13:26:32

参考文章:https://blog.csdn.net/baixingyubxy/article/details/125964986?spm=1001.2014.3001.5506

上面是详细讲解,我这篇是总结了他的代码,因为他没给整体代码 

所有代码:


#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <signal.h>

#define MAXFD 1024
#define PATH "/home/hadoop/qimo/"

struct mess {
    int type;
    int c;
};

// 声明get_filename函数
char* get_filename(char buff[]);
int sockfd, msgid, epfd;

void sig_fun(int signo)
{
    printf("got a signal %d\n", signo);
}

int socket_init()
{
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        return -1;
    }
    struct sockaddr_in saddr;
    memset(&saddr, 0, sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(8080);
    saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
    int res = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));
    if (res == -1)
    {
        printf("bind err\n");
        return -1;
    }
    res = listen(sockfd, 5);
    if (res == -1)
    {
        return -1;
    }
    return sockfd;
}

void* loop_thread(void* arg)
{
    while (1)
    {
        struct mess m;
        msgrcv(msgid, &m, sizeof(int), 1, 0);//从消息队列中读取消息
        int c = m.c;
        if (c == sockfd)
        {
            struct sockaddr_in caddr;
            int len = sizeof(caddr);
            int cli = accept(sockfd, (struct sockaddr*)&caddr, &len);
            if (cli < 0)
            {
                continue;
            }
            epoll_add(epfd, cli);
        }
        else
        {
            char buff[1024] = { 0 };
            int n = recv(c, buff, 1023, 0);
            if (n <= 0)
            {
                epoll_del(epfd, c);//调用移除描述符函数
                close(c);
                printf("close\n");
                continue;
            }
            char* filename = get_filename(buff);//调用资源名获取函数
            if (filename == NULL)
            {
                send_404status(c);//调用发送错误应答报文函数
                epoll_del(epfd, c);//调用移除描述符函数
                close(c);
                continue;
            }
            printf("filename:%s\n", filename);

            if (send_httpfile(c, filename) == -1)//调用发送正确应答报文函数
            {
                printf("主动关闭连接\n");
                epoll_del(epfd, c);
                close(c);
                continue;
            }
        }
        epoll_mod(epfd, c);//调用重置函数
    }
}

//添加描述符函数
void epoll_add(int epfd, int fd)
{
    struct epoll_event ev;
    ev.data.fd = fd;
    ev.events = EPOLLIN | EPOLLONESHOT;

    if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
    {
        printf("epoll add err\n");
    }
}

//移除描述符函数
void epoll_del(int epfd, int fd)
{
    if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL) == -1)
    {
        printf("epoll del err\n");
    }
}

//重置描述符函数
void epoll_mod(int epfd, int fd)
{
    struct epoll_event ev;
    ev.data.fd = fd;
    ev.events = EPOLLIN | EPOLLONESHOT;
    if (epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev) == -1)
    {
        printf("epoll mod err\n");
    }
}

char* get_filename(char buff[])
{
    char* ptr = NULL;
    char* s = strtok_r(buff, " ", &ptr);
    if (s == NULL)
    {
        printf("请求报文错误\n");
        return NULL;
    }
    printf("请求方法:%s\n", s);
    s = strtok_r(NULL, " ", &ptr);
    if (s == NULL)
    {
        printf("请求报文 无资源名字\n");
        return NULL;
    }
    if (strcmp(s, "/") == 0)
    {
        return "/index.html";
    }
    return s;
}

int send_httpfile(int c, char* filename)
{
    if (filename == NULL || c < 0)
    {
        send(c, "err", 3, 0);
        return -1;
    }

    char path[128] = { PATH };
    strcat(path, filename); //  /home/ubuntu/ligong/day12/index.hmtl
    int fd = open(path, O_RDONLY);
    if (fd == -1)
    {
        send_404status(c);
        return -1;
    }

    int size = lseek(fd, 0, SEEK_END);
    lseek(fd, 0, SEEK_SET);
    char head_buff[512] = { "HTTP/1.1 200 OK\r\n" };
    strcat(head_buff, "Server: myhttp\r\n");
    sprintf(head_buff + strlen(head_buff), "Content-Length: %d\r\n", size);
    strcat(head_buff, "\r\n"); //分隔报头和数据 空行
    send(c, head_buff, strlen(head_buff), 0);
    printf("send file:\n%s\n", head_buff);

    int num = 0;
    char data[1024] = { 0 };
    while ((num = read(fd, data, 1024)) > 0)
    {
        send(c, data, num, 0);
    }
    close(fd);

    return 0;
}

int send_404status(int c)
{
    int fd = open("err404.html", O_RDONLY);
    if (fd == -1)
    {
        send(c, "404", 3, 0);
        return 0;
    }

    int size = lseek(fd, 0, SEEK_END);
    lseek(fd, 0, SEEK_SET);
    char head_buff[512] = { "HTTP/1.1 404 Not Found\r\n" };
    strcat(head_buff, "Server: myhttp\r\n");
    sprintf(head_buff + strlen(head_buff), "Content-Length: %d\r\n", size);
    strcat(head_buff, "\r\n"); //分隔报头和数据 空行
    send(c, head_buff, strlen(head_buff), 0);

    char data[1024] = { 0 };
    int num = 0;
    while ((num = read(fd, data, 1024)) > 0)
    {
        send(c, data, num, 0);
    }
    close(fd);
    return 0;
}

int main()
{
    signal(SIGPIPE, sig_fun);
    sockfd = socket_init();
    if (sockfd == -1)
    {
        exit(0);
    }
    msgid = msgget((key_t)1234, IPC_CREAT | 0600);
    if (msgid == -1)
    {
        exit(0);
    }
    pthread_t id[4];
    for (int i = 0; i < 4; i++) //循环创建线程池
    {
        pthread_create(&id[i], NULL, loop_thread, NULL);
    }
    epfd = epoll_create(MAXFD); //创建内核事件表
    if (epfd == -1)
    {
        printf("create epoll err\n");
        exit(0);
    }
    epoll_add(epfd, sockfd); //调用封装的函数添加描述符和事件
    struct epoll_event evs[MAXFD];
    while (1)
    {
        int n = epoll_wait(epfd, evs, MAXFD, -1); //获取就绪描述符
        if (n == -1)
        {
            continue;
        }
        else
        {
            struct mess m;
            m.type = 1;
            for (int i = 0; i < n; i++)
            {
                m.c = evs[i].data.fd;
                if (evs[i].events & EPOLLIN)
                {
                    msgsnd(msgid, &m, sizeof(int), 0); //向消息队列发送消息
                }
            }
        }
    }
}

 编译命令

我的源代码名字是 test1.c

 gcc -pthread test1.c -o test1

 修改内容

文件夹所有内容如下”

添加index.html

<html>
     <head>
         <meta charset=utf8>
          <title>baixingyu</title>
          </head>
      <body background="R-C.jpg">
             <center>
                 <h2>nazhanpeng--hhhhh</h2>
                 </center>

                <input style="width:300px;height:150px;text-align-center;font-size:30px"  type="text" placeholder="请输入用户名">
                <input  style="width:300px;height:150px;text-align-center;font-size:30px"  type="password" placeholder="请输入密码">
                <a href="test.html">下一页</a>

                </body>
      </html>

添加test.html

 <html>
      <head>
         <meta charset=utf8>
         <title>测试</title>
          </head>
         <body>
             <center>
                 <h2>小狗小狗
                 </center>
                   <a href="index.html">返回</a>
              </body>
 </html>

添加:err404.html 

 <html>
     <head>
          <meta charset=utf8>
          <title>访问失败</title>
          </head>
          <body background="1.jpg">
              <center>
                  <h2>页面走丢了</h2>
                  </center>
              </body>
</html>

 修改访问路径

改成你的存放源文件的目录

命令  pwd

 修改端口号

 查看端口号是否占用,如果有返回值就是占用,没有显示就是没有占用,被占用了自行修改就可以

sudo netstat -tuln | grep :8080

当前目录上传两张图片

1张改名为1.jpg

1张改名为R-C.jpg

mv  原来的图片.jpg    要改的名字.jpg

访问演示:

index.html

test.html

小bug:访问不存在的页面,没有出现err404.html

可以自行修改,

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1324199.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

echarts地图map点击某一区域设置选中颜色/select选中文字颜色设置无效

选中区域为红色&#xff0c;字体为白色 1.selectedMode: ‘single’,设置单选&#xff0c;多选&#xff0c;不选中 2.series/map/select属性 series: [{type: map,map: area,//单选selectedMode: single,aspectScale: 0.73,layoutCenter: [50%, 51%], //地图位置layoutSize: …

CEC2013(python):五种算法(OOA、WOA、GWO、DBO、HHO)求解CEC2013(python代码)

一、五种算法简介 1、鱼鹰优化算法OOA 2、鲸鱼优化算法WOA 3、灰狼优化算法GWO 4、蜣螂优化算法DBO 5、哈里斯鹰优化算法HHO 二、5种算法求解CEC2013 &#xff08;1&#xff09;CEC2013简介 参考文献&#xff1a; [1] Liang J J , Qu B Y , Suganthan P N , et al. Pro…

量子登月计划!Infleqtion与日本JST研发中性原子量子计算机

​&#xff08;图片来源&#xff1a;网络&#xff09; 美国量子信息公司Infleqtion&#xff0c;已被日本科学技术振兴机构&#xff08;JST&#xff09;选定为“量子登月计划”唯一的外国量子计算合作伙伴。该计划旨在增强日本的量子技术能力&#xff0c;预计将在2050年之前对日…

WinDbg调试异常(!!! second chance !!!)

以前使用windbg调试样本时不时会遇到异常并提示(!!! second chance !!!),之前也尝试查找过原因但是并没有找到,一直十分郁闷。这次又出现了异常,有时间查找原因并发现了问题所在,于是记录下分析过程。 起因 在调试一个样本,每次用windbg调试都会出现: 但是使用x64dbg调…

java-sec-code中jwt

java-sec-code中jwt jwt漏洞首先需要爆破出密钥&#xff0c;然后在进行伪造&#xff0c;由于这里是白盒&#xff0c;不做爆破演示&#xff0c;直接利用 创建jwt属性值 http://127.0.0.1:8080/jwt/createToken从jwt属性值中解密获取user值 http://127.0.0.1:8080/jwt/getName…

docker安装sonar后集成本地代码进行质量分析

背景 在完成代码后&#xff0c;想做一个较低层级的代码自检&#xff0c;来完善自己代码的质量 技术选型 在结合现有项目情况下&#xff0c;结合Jenkins走CI CD过程&#xff0c;选择了sonarqube 安装 下载地址:自己搜 安装教程我来出,首先sonarqube完整的过程分了两部分&…

网络时代的新宠

当今社会&#xff0c;随着科技的不断进步和互联网的普及&#xff0c;手机已经成为了人们生活中不可或缺的一部分。它不仅仅是一个通信工具&#xff0c;更是娱乐、学习和获取信息的利器。而其中&#xff0c;手机无人直播更是近年来备受关注的热门话题。 直播&#xff0c;一种实…

程序员必知!开放封闭原则的实战应用与案例分析

开放封闭原则是面向对象设计中的重要原则之一&#xff0c;它要求软件实体&#xff08;类、模块、函数等&#xff09;应该对扩展开放&#xff0c;但对修改关闭。这意味着当需要添加新功能时&#xff0c;不应该修改现有的代码&#xff0c;而是应该通过扩展来实现。这可以通过使用…

图片编辑文字用什么软件?带你了解这5个

图片编辑文字用什么软件&#xff1f;在当今数字化的时代&#xff0c;图片编辑已经成为我们日常生活中不可或缺的一部分。有时候&#xff0c;我们需要在图片上添加文字&#xff0c;以增强图片的视觉效果或传达特定的信息。那么&#xff0c;有哪些可以在图片上编辑文字的软件呢&a…

使用postman时,报错SSL Error: Unable to verify the first certificate

开发中使用postman调用接口&#xff0c;出现以下问题&#xff0c;在确认路径、参数、请求方式均为正确的情况下 解决方法 File - Settings -> SSL certification verification 关闭 找到图中配置&#xff0c;这里默认是打开状态&#xff0c;把它关闭即可&#xff1a;ON …

mysql:查询服务器当前打开的连接数量

使用命令show global status like Threads_connected;可以查询mysql服务器当前打开的连接数量。 例如&#xff0c;查询如下&#xff1a; 启动应用&#xff0c;连接数据库&#xff0c;占用了1个连接&#xff0c;再查询如下&#xff1a; 由输出可以看出&#xff0c;打开的连接…

02 ModBus TCP

目录 一、ModBus TCP 一帧数据格式 二、0x01 读线圈状态 三、0x03读保持寄存器 四、0x05写单个线圈 五、0x06 写单个寄存器 六、0x0f写多个线圈 七、0x10&#xff1a;写多个保持寄存器 八、通信过程 九、不同modbus通信模式的应用场景 一、ModBus TCP 一帧数据格式 其…

JNI逆向

IDA&#xff1a;JNI类型转换 1.IDA高版本&#xff08;IDA 高版本内置了定义的JNI结构体; 如果没有的话&#xff0c;在Views->Open subviews -> Type Libraries 中添加Android ARM的lib即可&#xff09; 解决方法: 只需要对JNIEnv 指针&#xff08;JNIEnv * &#xff09…

jQuery实现轮播图代码

简述 一个简单的jQuery轮播图代码,首先,定义了一个slideshow-container的div容器,其中包含了所有轮播图幻灯片。每个幻灯片都包含一个mySlides的类名,并且使用CSS将其隐藏。然后,使用JavaScript代码来控制幻灯片的显示和隐藏。在showSlides()函数中,遍历所有幻灯片并将它…

DDD领域驱动设计(二)

软件系统复杂性的应对 解决复杂和大规模软件的武器可以粗略的归位三种:抽象 分治和知识 抽象: 使用抽象能够精简问题空间&#xff0c;而且问题越小越容易理解。比如你去一个地方 一开始的时候并不需要确定用什么方式到达。分治: 类似算法里面的dp用的就是分治的想法。分割后的…

构建陪诊预约系统:技术实战指南

在医疗科技的飞速发展中&#xff0c;陪诊预约系统的应用为患者和陪诊人员提供了更为便捷和贴心的服务。本文将带领您通过技术实现&#xff0c;构建一个简单而实用的陪诊预约系统&#xff0c;以提升医疗服务的效率和用户体验。 技术栈选择 在开始之前&#xff0c;我们需要选择…

Halcon求三点中心,三角形重心、三角形外接圆外心和内切圆内心

本文涉及几何问题&#xff0c;求角平分线&#xff0c;垂直平分线以及中线&#xff0c;不止可以应用于点和三角形&#xff0c;其他需求可选择性提取。 求角平分线&#xff1a;http://t.csdnimg.cn/QYZOK 求垂直平分线&#xff1a;http://t.csdnimg.cn/A4wWD 三角形的重心&…

JDK bug:ciObjectFactory::create_new_metadata:原因完全解析

文章目录 1、问题2.详细日志2.关键日志3.结论4.JDK&#xff1a;bug最终bug链接&#xff1a; 京东遇到过类似bug各位大佬如果有更详细的解答可以留言。 1、问题 服务不通&#xff0c;接口404&#xff0c;查看日志有一下截图&#xff0c;还有一个更详细的日志 2.详细日志 # #…

如何在公网环境下使用Potplayer访问本地群晖webdav中的影视资源

文章目录 本教程解决的问题是&#xff1a;按照本教程方法操作后&#xff0c;达到的效果是&#xff1a;1 使用环境要求&#xff1a;2 配置webdav3 测试局域网使用potplayer访问webdav3 内网穿透&#xff0c;映射至公网4 使用固定地址在potplayer访问webdav ​ 国内流媒体平台的内…

青少年CTF-qsnctf-Web-Queen

题目环境&#xff1a; 题目难度&#xff1a;★★ 题目描述&#xff1a;Q的系统会不会有漏洞&#xff1f; 看到了登录窗口&#xff0c;使用burp suite工具进行抓包 burp suite抓包 admin 1 Repeater重放Send放包 Your IP is not the administrator’s IP address! 您的IP不是管理…