光城归来之C语言开发网站

news/2024/5/13 20:05:29/文章来源:https://blog.csdn.net/guangcheng0312q/article/details/100117581

C语言开发网站

0.导语

最近要把防火墙项目做个页面,而底层全部c语言实现,那么就得做个web页面,想了一下,C大法这么厉害,也应该可以的,然后大家就见到了这篇文章。

本篇文章主要讲使用C语言如何开发网站,CGI,Nginx+CGI如何部署等问题。

1.Socket通信

初探网站开发,直接上手熟悉的Socket通信编程,这方面网上资料非常多。以网上一张图片为例:

640?wx_fmt=other

图片来自:https://www.jianshu.com/p/dd580395bf11

本次实践以Get/Post提交表单为例,学习如何解析Html,后端与前端如何通信,Socket如何使用的问题。

直接先放主函数,然后再从每个函数讲解。

 1int main(){2    //1.创建监听套接字,返回是套接字描述符3    int sockfd = create_listenfd();4    int fd;5    while (1){6        //2.等待客户端响应7        int fd = accept(sockfd,NULL,NULL);8        //3.处理客户端发来的请求9        handle_request(fd);
10        close(fd);
11    }
12    close(sockfd);
13}

Socket操作分别为:

  • 创建监听套接字,返回是套接字描述符

  • 接收客户端发来的请求

  • 处理客户端发来的请求

上述便是Socket通信的核心三步骤。

1.1 创建套接字

下面一一来分析上述三步如何写。

引入相关头文件

1#include <sys/types.h>
2#include <sys/socket.h>

核心函数解析

(1)获取一个socket descriptor

 1/**2获取一个socket descriptor3@params:4    domain: 此处固定使用AF_INET5    type: 此处固定使用SOCK_STREAM6    protocol: 此处固定使用07@returns:8    nonnegative descriptor if OK, -1 on error.9*/
10int socket(int domain, int type, int protocol);

(2)客户端socket向服务器发起连接

 1/**2客户端socket向服务器发起连接3@params:4    sockfd: 发起连接的socket descriptor5    serv_addr: 连接的目标地址和端口6    addrlen: sizeof(*serv_addr)7@returns:8    0 if OK, -1 on error9*/
10int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);

(3)绑定

 1/**2服务器socket绑定地址和端口3@params:4    sockfd: 当前socket descriptor5    my_addr: 指定绑定的本机地址和端口6    addrlen: sizeof(*my_addr)7@returns:8    0 if OK, -1 on error9*/
10int bind(int sockfd, struct sockaddr *my_addr, int addrlen)
11

(4)监听

1/**
2将当前socket转变为可以监听外部连接请求的socket
3@params:
4    sockfd: 当前socket descriptor
5    backlog: 请求队列的最大长度
6@returns:
7    0 if OK, -1 on error
8*/
9int listen(int sockfd, int backlog);

开始对上述操作进行封装,上述封装函数如下:

 1//监听套接字创建2int create_listenfd(){3    //创建Tcp连接4    int fd = socket(AF_INET,SOCK_STREAM,0);5    int option = 1;6    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));7    struct sockaddr_in sin;8    bzero(&sin,sizeof(sin));9    sin.sin_family=AF_INET;
10    sin.sin_port=htons(80);
11    sin.sin_addr.s_addr=INADDR_ANY;
12
13    int res = bind(fd,(struct sockaddr *)&sin,sizeof(sin));
14    if (res==-1){
15        perror("bind");
16    }
17    listen(fd,100);
18    return fd;
19}

1.2 等待客户端请求到达

等待客户端请求到达

 1/**2等待客户端请求到达,注意,成功返回得到的是一个新的socket descriptor,3而不是输入参数listenfd。4@params:5    listenfd: 当前正在用于监听的socket descriptor6    addr: 客户端请求地址(输出参数)7    addrlen: 客户端请求地址的长度(输出参数)8@returns:9    成功则返回一个非负的connected descriptor,出错则返回-1
10*/
11int accept(int listenfd, struct sockaddr *addr, int *addrlen);

在main函数中,使用while 1循环来进行等待:

1while (1){
2    int fd = accept(sockfd,NULL,NULL);
3}

1.3 处理客户端发来的请求

上述完成后,其实就可以运行代码,通过:

1gcc -o main main.c 
2./main

即可完成socket的web server搭建,而客户端与服务端的更多交互操作,则需要更深入的学习,那么接下来就是来做这方面工作的。

首先来看一下我们的运行结果:

640?wx_fmt=png

 

index.html图

640?wx_fmt=png

 post图

640?wx_fmt=png

 info.html图

640?wx_fmt=png客户端post前服务端接受数据图

640?wx_fmt=png

客户端post后服务端接受数据图

该函数完成了如下操作:

分别有两个页面,分别是index.htmlinfo.html

当第一次打开index.html时候,会通过get方式获取相关资源,如下图所示:

我们看到了获取index.html与2.jpg,所以我们看到了index页面信息。

而当我们发送post请求跳转到info.html时,我们会在info.html中看到post后的数据。

接下来就来看代码如何实现:

首先来看服务器端如何获取数据呢(也就是终端打印数据):

1char buffer[40*1024]={0};
2int nread=read(fd,buffer,sizeof(buffer));
3printf("读到的请求是:\n");
4printf("%s",buffer);
5printf("\n--------------------\n");
6sscanf(buffer,"%s /%s HTTP/1.1",method,filename);

这里直接通过read函数传递一个socket描述符,然后通过read便可获取到当前index.html的数据。

接下来就是get请求:

在上述sscanf函数中,我们解析出来了文件名与请求方法,然后根据请求方法做判断即可!

打开文件并发送该文件内容给浏览器,浏览器便可以接收到服务器端的响应数据!

 1char filename[10]={0};2char method[10]={0};34if(strcmp(method,"GET")==0){56    printf("\n解析出来的文件名是%s\n",filename);7    char mime[40*1024]={0};8    get_filetype(filename,mime);9    char response[40*1024]={0};
10
11    //\r\n\r\n表示换行后有一个空行
12    sprintf(response, "HTTP/1.1 200 OK\r\nContent-Type: %s\r\n\r\n", mime);
13    int headlen = strlen(response);
14    //打开文件,读取内容,构建响应,发回给客户端
15    int filefd = open(filename,O_RDONLY);
16    int filelen = read(filefd,response+headlen,sizeof(response)-headlen);
17
18    //发送响应头+内容
19    write(fd,response,headlen+filelen);
20    close(filefd);
21
22}

最后就是post请求:

上述我们通过post数据后到了info.html页面,那么这个如何做到的呢,就是通过解析post方法,然后对客户端,也就是浏览器做出响应即可!

 1char username[50] = { 0 };2char sex[50] = { 0 };3char email[50] = { 0 };4else if(strcmp(method,"POST")==0){5    char response[40*1024]={0};6    char mime[40*1024]={0};7    get_filetype(filename,mime);8    //\r\n\r\n表示换行后有一个空行9    sprintf(response, "HTTP/1.1 200 OK\r\nContent-Type: %s\r\n\r\n", mime);
10    int headlen = strlen(response);
11    char *postbuffer = strstr(buffer, "username=");
12    if(postbuffer){
13        // char * after = strchr(buffer, '&');
14        printf("------>%s\n",postbuffer);
15        // printf("------>%s\n",postbuffer+9);
16        char *sexbuffer = strstr(postbuffer, "&sex=");
17        char *emailbuffer = strstr(sexbuffer, "&email=");
18        printf("email:%s\n",emailbuffer);
19        strncpy(username,(const char *)postbuffer,strlen(postbuffer)-strlen(sexbuffer));
20        printf("用户名=%s\n",urldecode(username+9));
21        strncpy(sex,(const char *)sexbuffer,strlen(sexbuffer)-strlen(emailbuffer));
22        printf("性别=%s\n",urldecode(sex));
23        printf("邮箱=%s\n",urldecode(emailbuffer+7));
24        // char *email = strstr(buffer, "&email=");
25        // int sex_email = email-sex;
26    }
27    char *res[100]={0};
28    //发送数据给浏览器
29    sprintf(res,"<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><title>结果</title></head><body><p>POST结果:%s</p></body></html>",urldecode(postbuffer));
30    sprintf(response,"%s",res);
31    write(fd,response,headlen+strlen(res));
32    printf("%s\n",response);
33
34    // close(filefd);
35    printf("\n解析出来的文件名是%s\n",filename);
36
37}

除此之外,上述post后,碰到中文会出现乱码,以%的数据发送了过去,也就是通常的url编码与解码,这里直接用c实现解码函数即可:

 1// 解码url2char * urldecode(char url[])3{4    int i = 0;5    int len = strlen(url);6    int res_len = 0;7    char res[BURSIZE];8    for (i = 0; i < len; ++i)9    {
10        char c = url[i];
11        if (c != '%')
12        {
13            res[res_len++] = c;
14        }
15        else
16        {
17            char c1 = url[++i];
18            char c0 = url[++i];
19            int num = 0;
20            num = hex2dec(c1) * 16 + hex2dec(c0);
21            res[res_len++] = num;
22        }
23    }
24    res[res_len] = '\0';
25    strcpy(url, res);
26    return url;
27}

最后就会得到post后的含有特殊字符与中文的结果!

2.CGI+Nginx

2.1 概念初探

CGI

通用网关接口Common Gateway Interface/CGI描述了客户端和服务器程序之间传输数据的一种标准,可以让一个客户端,从网页浏览器向执行在网络服务器上的程序请求数据。CGI 独立于任何语言的,CGI 程序可以用任何脚本语言或者是完全独立编程语言实现,只要这个语言可以在这个系统上运行。Unix shell script, Python, Ruby, PHP, perl, Tcl,C/C++, 和 Visual Basic 都可以用来编写 CGI 程序。

如下图所示:

640?wx_fmt=png

FastCGI

快速通用网关接口(Fast Common Gateway Interface/FastCGI)是通用网关接(CGI)的改进,描述了客户端和服务器程序之间传输数据的一种标准。FastCGI致力于减少Web服务器与CGI程式之间互动的开销,从而使服务器可以同时处理更多的Web请求。与为每个请求创建一个新的进程不同,FastCGI使用持续的进程来处理一连串的请求。这些进程由FastCGI进程管理器管理,而不是web服务器。

640?wx_fmt=png

Nginx

Nginx是异步框架的Web服务器,也可以用作反向代理,负载平衡器 和 HTTP缓存。

Nginx+CGI

nginx 不能直接执行外部可执行程序,并且cgi是接收到请求时才会启动cgi进程,不像fastcgi会在一开就启动好,这样nginx天生是不支持 cgi 的。nginx 虽然不支持cgi,但它支持fastCGI。所以,我们可以考虑使用fastcgi包装来支持 cgi。原理大致如下图所示:pre-fork几个通用的代理fastcgi程序——fastcgi-wrapper,fastcgi-wrapper启动执行cgi然后将cgi的执行结果返回给nginx(fork-and-exec)。

640?wx_fmt=png

fastcgi-wrapper安装:进入下面地址:

https://github.com/gnosek/fcgiwrap

1autoreconf -i
2./configure
3make && make install

启动fastcgi-wrapper

1spawn-fcgi -f /usr/local/sbin/fcgiwrap -p 9000

nginx源码安装同上(不用执行第一行auto操作)。

安装完后,进入conf目录进行fcgiwrap配置:

1location ~ ^/cgi-bin/.*$ {
2    root /home/light/nginx/; # 填写自己的nginx目录
3    #cgi path 
4    if (!-f $document_root$fastcgi_script_name) {
5        return 404;
6    }
7    fastcgi_pass 127.0.0.1:9000;
8    include fastcgi.conf;
9}

在nginx目录下新建一个cgi-bin目录用于放置cgi程序。

编写cgi程序main.c

 1#include <stdio.h>2#include <stdlib.h>34int main(void)5{6    int count = 0;7    printf("Content-type: text/html;charset=utf-8\r\n"8        "\r\n"9        "<title>光城第一次使用CGI!</title>"
10
11        "<h1>光城第一次使用CGI!</h1>"
12        "Request number %d running on host <i>%s</i>\n",
13        ++count, getenv("SERVER_NAME"));
14    return 0;
15}

编译程序:

1gcc -o main main.c

开始部署,移动main到cgi-bin目录:

然后启动nginx:

1./sbin/nginx

打开浏览器:

640?wx_fmt=png

看到如上页面,成功!

640?wx_fmt=png

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

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

相关文章

您值得收藏的关系代数与Sql练习网站及实战操作

MySQL学习仓库Up-Up-MySQL,这是一个学习MySQL从入门实战到理论完善,再到精通的一个仓库,后面会把MySQL的学习资料上传上去!欢迎大家star与fork起来!仓库地址:https://github.com/Light-City/Up-Up-MySQL也可…

phpstudy+wordpress搭建网站

文章目录实验环境为什么选择2018安装phpstudy2018wordpress准备工作配置phpstudy配置数据库搭建wordpress优化设置更简域名主题与插件关闭自动更新设置未完待续实验环境 win10虚拟机,phpstudy2018,wordpress,VScode 为什么选择2018 网上很…

wordpress搭建网站(二)

文章目录添加域名重置密码添加用户注册功能开启openssl订阅邮箱注册邮件设置主页,添加登录入口本文为上一篇 phpstudywordpress搭建网站的续写,因为CSDN经常修改后因为各种原因无法过审,所以这里新开一篇。添加域名 一直输入IP地址加目录比较…

C++提效网站

C提效网站大家好,我是光城,统一回复:C那些事网站服务器到期,暂时关闭,大家直接阅读github或公众号内容即可。https://github.com/Light-City/CPlusPlusThings今日将会给大家推荐C日常工作/学习当中的一些网站&#xff…

这些价值上亿美元的网站,背后居然都只有一个程序员!

一个程序员,能顶一个团队,你一定想不到 你一定用过Google吧?有没有觉得这个页面极其简单,仿佛一个程序员就可以做出来? 然而事实并非如此,这个页面背后有个名叫Google Web Servers的服务,有着上…

不是 HTTPS 拖慢网站速度,而是优化做的不够优秀

HTTPS(全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道,简单讲是 HTTP 的安全版,即 HTTP 下加入 SSL 层。 HTTPS 的安全基础是 SSL,因此加密的详细内容…

如何使用在腾讯云申请的域名配合自己的电脑搭建自己的网站

首先在腾讯云购买一个域名,例如我的www.xxtt.cn,购买成功后,实名认证后出现下图:刚开始的时候服务状态应该是审核中,然后就是一直等待,等到审核通过后才可以继续下面的操作 当服务状态变为正常后&#xff0…

BugkuCTF-web-网站被黑 writeup

御剑拿后台,bp爆破 题目描述 解题思路 解题链接:http://123.206.87.240:8002/webshell/ 打开链接有一个炫酷的网页,,, 拿出御剑一顿扫描,得到后台网址 http://123.206.87.240:8002/webshell/shell.php …

给你的网站“加把锁” 动态口令轻松实现

转载自:http://www.chinaz.com/web/2012/0612/257136.shtml 随着网络的全面普及,网络安全问题也日趋严峻。暨著名的技术交流社区CSDN爆出600余万用户明文密码暴露事件之后,天涯社区4000万用户明文密码也泄漏于世,紧跟着人人网、开…

md5解密网站大全

感觉这个挺全的,记下以后备用 以前记得见过一个国外站 就是收集MD5的,你也可以提交MD5上去 让他给你破解.但是后来把网址忘了. 前几天跟朋友们在群里说起来这事了 刚才又想起来了,就找了找. 这次记下来,以免再忘记. 也把我见过的这类的网站记到一块. 国内的此类网站…

三款国外超赞的在线编程教学网站大PK

为了能够高效地学习各种技术和编程,掌握几个非常不错的网站还是很有必要的。本文我们将推荐3个非常不错的技术网站,Codecademy、CodeSchool、 TeamTreeHouse,让你告别编程小白,带你进入神奇的编程世界。 有句俗语叫:“…

网站架构

使用PHP开发一个门户站点,周期是三天,我差点想找个炸药包拿出来给叔闻一下。 在叔翘着二郎腿辱骂下,我终于带领一个小胖子在3天内完成了这个雏形。 由于备案还在申请中,所以只能用IP的方式看一下了。输入以下地址:ht…

《特别推荐》10套精美的免费网站后台管理系统模板

大部分的 Web 应用和动态网站都需要一个后台管理系统用于管理前台界面的信息展示以及用户信息。管理后台的设计虽然不像前台界面那样要求设计精美,但是也需要有清晰的管理模块划分,这样使用后台管理系统的人员才能够方便的进行操作和管理。下面收集了十款…

jeecms网站导航栏

采用jeecms建站的朋友都知道,jeecms网站导航栏是通过标签循环出来的,当栏目分多级时,或者顶级栏目下有多个子栏目时, jeecms系统默认自带的模板应用的标签并不是下拉的,很多用户想达到如jeecms官网导航栏下拉的效果&a…

瞬时响应:网站的高性能架构

瞬时响应:网站的高性能架构 什么叫高性能的网站? 两个网站性能架构设计方案:A方案和B方案,A方案在小于100个并发用户访问时,每个请求的响应时间是1秒,当并发请求达到200的时候,请求的响应时间…

大型网站--负载均衡架构

大型网站--负载均衡架构 2013-10-14 08:08 by 贤达, 7213 阅读, 32 评论, 收藏, 编辑 负载均衡 (Load Balancing) 负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处…

网站压力测试工具Jmeter安装与使用

系统是Windows XP 配置此工具前,需要先在机器上安装jdk 如下是在jdk1.7的基础上配置的; 安装步骤如下: 第一步:解压apache-jmeter-2.8.zip文件至c盘,本文解压至C:\jmeter2.8目录下。 第二步:桌面上选择“我…

开发者必备:测试网站速度的五个免费在线工具

如果你认为一个网站建成后,工作就已经完成,你就大错特错了。你需要不断监测其可用性和可访问性,一个小问题,可能毁了一切。而网页载入速度对于一个网站来讲至关重要,试想一下,你喜欢进一个需要很长时间才载…

你想建设一个能承受500万PV/每天的网站吗?如果计算呢?

http://elf8848.iteye.com/blog/967049 你想建设一个能承受500万PV/每天的网站吗? 500万PV是什么概念?服务器每秒要处理多少个请求才能应对?如果计算呢? PV是什么: PV是page view的简写。PV是指页面的访问次数&#…

css php 网站设计,HTML,CSS,PHP和JavaScript –网站设计

网站设计的支柱一直以来,软件工程都是艺术与科学的融合。计算机的发展见证了许多编程语言的发展。大量的Web编程语言尤其会使新手感到困惑。如果您是新手,则不必担心,因为本文将告诉您构建美观且功能强大的网站所需的语言。HTML和CSSHTML代表…