当前位置: 首页 > news >正文

网站公司怎么做业务推广运营怎么做

网站公司怎么做业务,推广运营怎么做,怎样开物流网站,网站制作那家便宜本文使用cgi库编写cgi服务,再使用nginx进行转发。两者结合,实现简单的get请求和post请求的web服务。 问题提出 近年笔者实现的web服务,基本是用golang、nodejs语言。C/C的没有真正做过,为补充技术栈,一直想做。想了几…

本文使用cgi库编写cgi服务,再使用nginx进行转发。两者结合,实现简单的get请求和post请求的web服务。

问题提出

近年笔者实现的web服务,基本是用golang、nodejs语言。C/C++的没有真正做过,为补充技术栈,一直想做。想了几年,现在因某些缘故,不能只想了,于是抽出时间研究一下。

设计思路

1、用cgi库实现简单的后端业务服务,提供get和post请求。端口端口为9000。

2、用spawn-fcgi启动服务。

3、使用nginx做转发,nginx为容器方式运行,对外端口为87,内部端口为9000。

4、上述服务运行在虚拟机中,在本地物理机使用curl测试。

实践

依赖库下载编译

本业务程序需使用spawn-fcgi和fcgi-2.4.1这2个库(工具)。

spawn-fcgi下载地址:http://download.lighttpd.net/spawn-fcgi/releases-1.6.x/spawn-fcgi-1.6.4.tar.gz

fcgi-2.4.1 下载地址:https://github.com/FastCGI-Archives/fcgi2/releases,具体为:https://github.com/FastCGI-Archives/FastCGI.com/blob/master/original_snapshot/fcgi-2.4.1-SNAP-0910052249.tar.gz

编译简要步骤:

tar xf spawn-fcgi-1.6.4.tar.gz
cd spawn-fcgi-1.6.4
./configure --prefix=/home/latelee/tools/cgi
make
make installtar xf fcgi-2.4.1-SNAP-0910052249.tar.gz
cd fcgi-2.4.1-SNAP-0910052249
./configure --prefix=/home/latelee/tools/cgi
make
make install

注1:在fcgi-2.4.1-SNAP-0910052249/libfcgi/fcgio.cpp文件中添加#include <stdio.h>,否则编译失败,提示fcgio.cpp:70:72: error: 'EOF' was not declared in this scope

注2:如果系统上没有g++编译,则不会生成libfcgi++.so.0。库位于fcgi-2.4.1-SNAP-0910052249/libfcgi/.libs/

安装后得到文件:

$pwd
/home/latelee/tools/cgi$ tree -L 2
.
├── bin
│   ├── cgi-fcgi
│   └── spawn-fcgi
├── include
│   ├── fastcgi.h
│   ├── fcgiapp.h
│   ├── fcgi_config.h
│   ├── fcgimisc.h
│   ├── fcgio.h
│   ├── fcgios.h
│   └── fcgi_stdio.h
├── lib
│   ├── libfcgi.a
│   ├── libfcgi++.a
│   ├── libfcgi.la
│   ├── libfcgi++.la
│   ├── libfcgi.so -> libfcgi.so.0.0.0
│   ├── libfcgi++.so -> libfcgi++.so.0.0.0
│   ├── libfcgi.so.0 -> libfcgi.so.0.0.0
│   ├── libfcgi++.so.0 -> libfcgi++.so.0.0.0
│   ├── libfcgi.so.0.0.0
│   └── libfcgi++.so.0.0.0
└── share└── man	

在Makefile中直接使用上述库路径,由于要使用spawn-fcgi,因此将其拷贝到系统PATH目录中。

业务程序代码

核心C++代码如下,由于是测试用,因此代码不做过多的设计。

#include <fcgi_stdio.h>
#include <fcgiapp.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <ctype.h>
#include <time.h>#include "log.h"#define THREAD_COUNT 4
#define VERSION "1.0.0"// 获取编译时间字符串
const char* get_build_time() {static char build_time[64] = {0};if (build_time[0] == '\0') {// 使用 __DATE__ 和 __TIME__ 宏获取编译时间snprintf(build_time, sizeof(build_time), "%s %s", __DATE__, __TIME__);}return build_time;
}char* get_request_path(FCGX_Request* request) {char* request_uri = FCGX_GetParam("REQUEST_URI", request->envp);if (!request_uri) return strdup("");// 去除查询字符串char* question_mark = strchr(request_uri, '?');if (question_mark) {return strndup(request_uri, question_mark - request_uri);} else {return strdup(request_uri);}
}void send_response(FCGX_Request* request, const char* response) {FCGX_FPrintF(request->out, "%s", response);
}void handle_get(FCGX_Request* request) {char* path = get_request_path(request);log_printf("GET request for path: %s\n", path);if (strcmp(path, "/info") == 0) {// 返回版本信息char response[512];snprintf(response, sizeof(response),"Status: 200 OK\r\n""Content-Type: application/json\r\n\r\n""{\"service\": \"FastCGI Demo\", ""\"version\": \"%s\", ""\"build_time\": \"%s\", ""\"current_time\": \"%ld\"}",VERSION, get_build_time(), time(NULL));send_response(request, response);} else {send_response(request, "Status: 404 Not Found\r\n""Content-Type: text/plain\r\n\r\n""Endpoint not found. Try /info");}free(path);
}char* php_url_decode(const char* str) {if (!str) return NULL;char* result = (char*)malloc(strlen(str) + 1);char* dst = result;const char* src = str;while (*src) {if (*src == '+') {*dst++ = ' ';src++;} else if (*src == '%' && isxdigit(src[1]) && isxdigit(src[2])) {char hex[3] = {src[1], src[2], '\0'};*dst++ = (char)strtol(hex, NULL, 16);src += 3;} else {*dst++ = *src++;}}*dst = '\0';return result;
}char* parse_form_data(const char* data, const char* key) {if (!data || !key) return NULL;char* copy = strdup(data);char* token = strtok(copy, "&");char* result = NULL;while (token) {char* eq = strchr(token, '=');if (eq) {*eq = '\0';if (strcmp(token, key) == 0) {result = strdup(eq + 1);break;}}token = strtok(NULL, "&");}free(copy);return result;
}void handle_post(FCGX_Request* request) {char* path = get_request_path(request);log_printf("POST request received,path: %s\n", path);free(path);char* content_length_str = FCGX_GetParam("CONTENT_LENGTH", request->envp);int content_length = content_length_str ? atoi(content_length_str) : 0;if (content_length <= 0) {send_response(request, "Status: 411 Length Required\r\n""Content-Type: text/plain\r\n\r\n""Content-Length required");return;}char* post_data = (char*)malloc(content_length + 1);FCGX_GetStr(post_data, content_length, request->in);post_data[content_length] = '\0';char* decoded_data = php_url_decode(post_data);const char* key = "name";char* value = parse_form_data(decoded_data, key);char response[1024];snprintf(response, sizeof(response), "Status: 200 OK\r\n""Content-Type: application/json\r\n\r\n""{\"received\": \"%s\", \"%s\": \"%s\"}",post_data, key, value ? value : "not found");send_response(request, response);free(post_data);free(decoded_data);if (value) free(value);
}void process_request(FCGX_Request* request) {char* request_method = FCGX_GetParam("REQUEST_METHOD", request->envp);log_printf("Received %s request\n", request_method ? request_method : "unknown");if (strcmp(request_method, "POST") == 0) {handle_post(request);} else if (strcmp(request_method, "GET") == 0) {handle_get(request);} else {send_response(request, "Status: 405 Method Not Allowed\r\n""Content-Type: text/plain\r\n\r\n""Only GET and POST methods are supported");}
}void* handle_requests(void* arg) {FCGX_Request request;FCGX_InitRequest(&request, 0, 0);while (FCGX_Accept_r(&request) == 0) {process_request(&request);FCGX_Finish_r(&request);}return NULL;
}int main()
{// 初始化日志系统if (log_init() != 0) {fprintf(stderr, "Failed to initialize logging system\n");return EXIT_FAILURE;}log_printf("Server started. Version: %s, Build time: %s\n", VERSION, get_build_time());FCGX_Init();pthread_t threads[THREAD_COUNT];for (int i = 0; i < THREAD_COUNT; i++) {pthread_create(&threads[i], NULL, handle_requests, NULL);}for (int i = 0; i < THREAD_COUNT; i++) {pthread_join(threads[i], NULL);}log_printf("Server shutting down\n");// 清理日志系统log_cleanup();return 0;
}

其中,log_printf等是日志模块函数,不是重点,因此不列出。要说明的是,本次代码绝大部分是使用AI经多次迭代后得到的,其风格与笔者的稍有不同,但也不修改了(以证明使用AI)。不过,像char* post_data = (char*)malloc(content_length + 1);这种代码就无法生成正确的版本,要借助编译器修正。

鉴于笔者不太喜欢动态库,因此用静态库编译,Makefile核心要点:

LIBS    += /home/latelee/tools/cgi/lib/libfcgi.a
LDFLAGS += $(LIBS) -lpthread -lrt INC = ./ ./inc /home/latelee/tools/cgi/include

运行:

spawn-fcgi -p 9000 -n ./a.out

nginx转发

本次使用nginx容器进行转发,docker-compose文件如下:

version: '3.8'services:nginx-forward:image: registry.cn-shenzhen.aliyuncs.com/hxr/nginx:1.23.tbcontainer_name: nginx-forwardhostname: nginx-forwardrestart: always#command: "sleep 10000000"volumes:- ./log/nginx:/var/log/nginx- ./config/nginx.conf:/etc/nginx/nginx.conf- ./config/conf.d:/etc/nginx/conf.denvironment:- TZ=Asia/Shanghai- AA=aaaadddaadports:- 87:9000networks:- custom-net
networks:custom-net:driver: bridge

其中nginx.conf会加载nginx.conf目录下的文件,其下有http_cgi.conf配置文件,内容如下:

server {listen       9000;listen  [::]:9000;server_name  localhost;location / {fastcgi_pass 192.168.28.11:9000;include fastcgi_params;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;fastcgi_param PATH_INFO $fastcgi_script_name;# 允许POST请求fastcgi_param REQUEST_METHOD $request_method;fastcgi_param CONTENT_TYPE $content_type;fastcgi_param CONTENT_LENGTH $content_length;}# redirect server error pages to the static page /50x.html#error_page   500 502 503 504  /50x.html;location = /50x.html {root   /usr/share/nginx/html;}
}

其中关键的地方是指定后端业务程序IP和端口,可以是本机,也可以是同网络其它主机,但一定要正确。

fastcgi_pass 192.168.28.11:9000;

测试

本次使用curl进行测试。

get请求示例:

$ curl http://192.168.28.11:87/info
{"service": "FastCGI Demo", "version": "1.0.0", "build_time": "Apr  4 2025 22:17:22", "current_time": "1743776337"}

post请求示例:

$ curl -X POST -d "name=latelee&age=38" http://192.168.28.11:87/api
{"received": "name=latelee&age=38", "name": "latelee"}

可以看到,已经能正确处理请求了。

扩展知识

后续考虑使用Tengine替换nginx来实验,再后续可能考虑使用商密的SSL证书。

小结

总体上,用C/C++实现感觉有些麻烦,涉及东西也多。不如用golang来得直接。也正是如此,笔者负责的和web有关的工程,都不用C/C++。即使需要和底层动态库交互,也有相应的方法实现(可参考笔者写的golang有关文章),维护起来相对简单。如果出于性能方面的考虑,的确应用稍底层的语言,不过,就笔者在生产上使用的情况看,还没有出现因语言本身导致的性能问题,如果一定要举例,那就是因为日志模块没有用异步写入,导致处理请求整体耗时较高,虽然在秒级以内,但也不能接受,后来修正,再有本地缓存加持,单次处理可在20毫秒内完成。

nginx无法转发问题

起初没留意http_cgi.conf的配置,nginx的error.log有如下错误:

*8 upstream sent unsupported FastCGI protocol version: 72 while reading response header from upstream, client: 192.168.28.11, server: localhost, request: "POST /api HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "192.168.28.11:87"

信息里提到不支持FastCGI协议版本,或说nginx和自编的cgi程序协议版本不对。后来才发现是IP写错了。因为我的nginx使用容器启动,而配置文件的IP写成了127.0.0.1:9000,而恰好容器里监听的端口也是9000,就是说nginx的端口转给自己了。将IP改为主机IP即可解决问题。但当时调试时思路不够清晰,搞了好久才发现问题。

http://www.cadmedia.cn/news/11336.html

相关文章:

  • 网站建设服务条款中国疫情最新情况
  • 东莞软件有限公司湖南seo优化报价
  • 高端品牌网站建设建议百度seo排名优
  • 为企业进行网站建设方案国内seo服务商
  • 丽水网站建设报价seo技术培训教程视频
  • 网站建设 项目文档无货源网店怎么开
  • 东莞网站建设制作服务最好的推广平台是什么软件
  • 新泰网站定制优化大师下载电脑版
  • 温州网站建设费用什么是搜索引擎竞价推广
  • 关于电子商务的网站推广方案百度指数使用指南
  • 开发一个电商网站网络推广软件有哪些
  • 深圳做外贸网站免费的seo网站
  • 建设部网站从何时可以查询工程师证能让手机流畅到爆的软件
  • 可靠的常州网站建设seo检测
  • 南京自助建站google ads
  • 最近的男科医院是哪家医院南京seo按天计费
  • 如何建设论坛网站郑州百度推广代理公司
  • wordpress仿next主题黑帽seo是什么意思
  • 优化大师电脑版官网推广优化网站排名教程
  • 大连企业网站建站网站维护费用
  • 临沂在线上网站建设百度指数下载app
  • 网站建设响应式识图搜索在线 照片识别
  • 商业网站缩写搜索引擎广告推广
  • 公司logo设计图片素材微软优化大师
  • 做网站 赚钱多吗无线网络优化是做什么的
  • php开发手机端网站开发免费域名申请网站大全
  • 深圳龙岗今天新闻头条seo系统是什么意思
  • 高端手机网站建设需要多少钱今天的头条新闻
  • 徐州睢宁网站建设国内搜索引擎大全
  • 武汉 网站建设关键词搜索工具好站网