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

参考文章: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

可以自行修改,

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python Django Jet:优化 Django 后台管理

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 大家好&#xff0c;今天分享 Python 中的 Django Jet 库。 Github项目地址&#xff1a;https://github.com/geex-arts/django-jet Django Jet 是一个强大的 Django 后台管理界面扩展&#xff0c;旨在提供更现代…

人工智能125个常用名词解释

1 什么是人工智能 人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;是指计算机系统通过模拟人类的思维和行为来完成特定任务的技术和方法。人工智能的研究涉及多个学科&#xff0c;包括计算机科学、数学、心理学、哲学等领域。 人工智能可以被分为…

SVM —— 理论推导

SVM 支持向量线性可分最大间隔超平面最大间隔超平面的推导支持向量分类间隔的推导最优化问题 对偶问题拉格朗日乘子法强对偶性 SVM 优化软间隔解决问题优化目标及求解 核函数线性不可分核函数的作用常见核函数 SVM 算法优缺点 支持向量机&#xff08;Support Vector Machine&am…

Collecting package metadata (current_repodata.json): failed(解决方案)

如果有重装过anaconda&#xff0c;在C盘的用户目录下&#xff0c;会有一个名叫.condarc的文件会自动生成。 当使用conda install和conda create命令会出现下面的问题&#xff1a;Collecting package metadata (current_repodata.json): failed 解决方案&#xff1a; 1.打开Anac…

Leetcod面试经典150题刷题记录 —— 双指针篇

双指针篇 1. 验证回文串Python3 2. 判断子序列Python3双指针 3. 两数之和 II - 输入有序数组Python3 4. 盛最多水的容器Python3双指针 5. 三数之和 1. 验证回文串 题目链接&#xff1a;验证回文串 - leetcode 题目描述&#xff1a; 如果在将所有大写字符转换为小写字符、并移除…

Spring Cloud + Vue前后端分离-第6章 通用代码生成器开发

Spring Cloud Vue前后端分离-第6章 通用代码生成器开发 6-1 代码生成器原理介绍 1.增加generator模块&#xff0c;用于代码生成 2.集成freemarker 通用代码生成器开发 FreeMarker 是一款模版引擎&#xff0c;通过模板生成文件&#xff0c;包括html页面&#xff0c;excel …

基于vue+element-plus+echarts制作动态绘图页面(柱状图,饼图和折线图)

前言 我们知道echarts是一个非常强大的绘图库&#xff0c;基于这个库&#xff0c;我们可以绘制出精美的图表。对于一张图来说&#xff0c;其实比较重要的就是配置项&#xff0c;填入不同的配置内容就可以呈现出不同的效果。 当然配置项中除了样式之外&#xff0c;最重要的就是…

腾讯云debian服务器的连接与初始化

目录 1. 远程连接2. 软件下载3. 设置开机自启动 1. 远程连接 腾讯云给的服务器在安装好系统之后&#xff0c;只需要在防火墙里面添加一个白名单&#xff08;ip 或者域名&#xff09;就能访问了。 防火墙添加本机WLAN的IPv4白名单&#xff0c;本地用一个远程工具连接&#xff…

C++设计模式之——命令模式

命令模式 概念创建步骤示例示例一代码实现运行结果 示例二代码实现运行结果 示例三示例代码运行结果 示例四代码实现运行结果 应用场景 概念 命令模式是一种行为型设计模式&#xff0c;它允许将请求封装为一个对象&#xff0c;从而使得可以参数化客户端请求、将请求排队或者记…

npm login报错:Public registration is not allowed

npm login报错:Public registration is not allowed 1.出现场景2.解决 1.出现场景 npm login登录时,出现 2.解决 将自己的npm镜像源改为npm的https://registry.npmjs.org/这个&#xff0c;解决&#xff01;

安防视频云平台/可视化监控云平台EasyCVR获取设备录像失败,该如何解决?

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。GB28181音视频流媒体视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体可实现视频监控直播、视频轮播、视…

打响指针的第一枪:指针家族

前言 指针其实是我们学习C语言中最难的知识点&#xff0c;很多人在学习指针的时候会被绕晕&#xff0c;包括博主也是&#xff0c;当初百思不得其解&#xff0c;脑袋都要冒烟了&#xff0c;本来打算在学习指针的时候就写一篇博客&#xff0c;但是当初自己的能力还是没有办法去完…

harmonyOS 自定义组件基础演示讲解

上文 HarmonyOS组件属性控制 链式编程格式推荐我们讲了一些系统组件 可以传入一些事件和参数 来达到一些不同的效果 其实 我们还可以用自己写的组件 那么 组件这么写&#xff1f; 其实 我们的 page 内部结果 就是一个组件 harmonyOS的概念 万物皆组件 那么 我们就可以在他下面…

低代码软件开发的革命

一、前言 如果一个概念能在科技圈火起来&#xff0c;它往往兼具字面简明和内涵丰富的特征&#xff0c;并具有某种重塑产业格局的潜力。低代码&#xff08;Low Code&#xff09;就是这样一个典型。顾名思义&#xff0c;低代码是指少用代码&#xff0c;甚至不用代码&#xff0c;仅…

自动化测试 (五) 读写64位操作系统的注册表

自动化测试经常需要修改注册表 很多系统的设置&#xff08;比如&#xff1a;IE的设置&#xff09;都是存在注册表中。 桌面应用程序的设置也是存在注册表中。 所以做自动化测试的时候&#xff0c;经常需要去修改注册表 Windows注册表简介 注册表编辑器在 C:\Windows\regedit…

Netty入门基础知识

简介 Netty是一款高性能java网络编程框架&#xff0c;被广泛应用在中间件、直播、社交、游戏等领域。Netty对java NIO进行高级封装&#xff0c;简化了网络应用的开发过程。 stream与channel stream不会自动缓冲数据&#xff0c;channel会利用系统提供的发送缓冲区&#xff0c;接…

科创金融的向善力量:浙商银行多措并举赋能科创企业,打造科技金融服务生态圈

近日&#xff0c;浙商银行科技金融服务发布会在杭州举行。 发布会以“智汇科创&#xff0c;善行未来”为主题&#xff0c;围绕科技金融服务“向善”新生态&#xff0c;浙商银行重磅推出科创企业全图景服务方案&#xff0c;正式发布科创积分贷&#xff0c;与浙江大学联合发布人…

初冬天气变化大,长辈身上的这些小毛病千万不能轻视

心率、血氧、肺功能&#xff0c;甚至是一次次不起眼的咳嗽&#xff0c;背后都可能藏着健康问题。但是我们可以利用好手表上的健康检测功能&#xff0c;提前获知健康数据的变化&#xff0c;有的放矢&#xff0c;科学应对身体的不适&#xff0c;度过一个有准备的温暖冬天&#xf…

【JVM从入门到实战】(七)Java内存区域

运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域&#xff0c;称之为运行时数据区。 《Java虚拟机规范》中规定了每一部分的作用 线程不共享&#xff1a;程序计数器、虚拟机栈、本地方法栈 线程共享&#xff1a;方法区&#xff0c;堆 1. 程序计数器(Program Count…

定位咨询:企业市场竞争中的定海神针

什么是定位咨询?定位咨询能给企业带来什么帮助?在现代市场的激烈竞争中&#xff0c;定位咨询不仅是企业区分自己的重要工具&#xff0c;更是它们赢得市场份额的关键。以下是定位咨询的定义和几个核心方面&#xff0c;笔者将列举具体案例说明其重要性和实用性。 定位咨询的简单…