workflow是一个网络库,是一个基于C++在在线服务引擎
GitHub官网
运行hello world
1,创建一个server,构造函数入参传入一个入参是task的lamda函数,函数的内容会拿到response,并且可以在response中写body
2、server启动,绑定8888端口。这个时候浏览器输入端口可以访问这个服务,并且可以多次访问。3、很显然这个时候进程是在getchar()函数阻塞住了,它在等待用户从键盘输入字符,操作系统中断后将字符给到进程,进程继续执行,server stop
#include <stdio.h>
#include "workflow/WFHttpServer.h"
int main()
{
WFHttpServer server([](WFHttpTask *task) {
task->get_resp()->append_output_body("<html>Hello World!</html>");
});
if (server.start(8888) == 0) { // start server on port 8888
getchar(); // press "Enter" to end.
server.stop();
}
return 0;
}
MacBook下如何运行wget:
按照教程运行之后,有以下错误:
(base) ➜ tutorial git:(master) ✗ ./wget
dyld: Library not loaded: libworkflow.0.dylib
Referenced from: /Users/user/xx/workflow/tutorial/./wget
Reason: image not found
[1] 62365 abort ./wget
原因是运行的时候动态链接库路径没有配置,配置一下即可:
export DYLD_LIBRARY_PATH=/Users/xxx/Projects/workflow/_lib:$DYLD_LIBRARY_PATH
wget baidu即可运行成功:
(base) ➜ tutorial git:(master) ✗ ./wget http://www.baidu.com
GET HTTP/1.1 /
Host: www.baidu.com
Accept: */*
User-Agent: Wget/1.14 (linux-gnu)
Connection: close
HTTP/1.1 200 OK
Content-Length: 2381
Content-Type: text/html
Server: bfe
Date: Mon, 19 Feb 2024 17:33:17 GMT
Connection: close
wget源码
#include <netdb.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include "workflow/HttpMessage.h"
#include "workflow/HttpUtil.h"
#include "workflow/WFTaskFactory.h"
#include "workflow/WFFacilities.h"
#define REDIRECT_MAX 5
#define RETRY_MAX 2
void wget_callback(WFHttpTask *task)
{
protocol::HttpRequest *req = task->get_req();
protocol::HttpResponse *resp = task->get_resp();
int state = task->get_state();
int error = task->get_error();
switch (state)
{
case WFT_STATE_SYS_ERROR:
fprintf(stderr, "system error: %s\n", strerror(error));
break;
case WFT_STATE_DNS_ERROR:
fprintf(stderr, "DNS error: %s\n", gai_strerror(error));
break;
case WFT_STATE_SSL_ERROR:
fprintf(stderr, "SSL error: %d\n", error);
break;
case WFT_STATE_TASK_ERROR:
fprintf(stderr, "Task error: %d\n", error);
break;
case WFT_STATE_SUCCESS:
break;
}
if (state != WFT_STATE_SUCCESS)
{
fprintf(stderr, "Failed. Press Ctrl-C to exit.\n");
return;
}
std::string name;
std::string value;
/* Print request. */
fprintf(stderr, "%s %s %s\r\n", req->get_method(),
req->get_http_version(),
req->get_request_uri());
protocol::HttpHeaderCursor req_cursor(req);
while (req_cursor.next(name, value))
fprintf(stderr, "%s: %s\r\n", name.c_str(), value.c_str());
fprintf(stderr, "\r\n");
/* Print response header. */
fprintf(stderr, "%s %s %s\r\n", resp->get_http_version(),
resp->get_status_code(),
resp->get_reason_phrase());
protocol::HttpHeaderCursor resp_cursor(resp);
while (resp_cursor.next(name, value))
fprintf(stderr, "%s: %s\r\n", name.c_str(), value.c_str());
fprintf(stderr, "\r\n");
/* Print response body. */
const void *body;
size_t body_len;
resp->get_parsed_body(&body, &body_len);
fwrite(body, 1, body_len, stdout);
fflush(stdout);
fprintf(stderr, "\nSuccess. Press Ctrl-C to exit.\n");
}
static WFFacilities::WaitGroup wait_group(1);
void sig_handler(int signo)
{
wait_group.done();
}
int main(int argc, char *argv[])
{
WFHttpTask *task;
if (argc != 2)
{
fprintf(stderr, "USAGE: %s <http URL>\n", argv[0]);
exit(1);
}
signal(SIGINT, sig_handler);
std::string url = argv[1];
if (strncasecmp(argv[1], "http://", 7) != 0 &&
strncasecmp(argv[1], "https://", 8) != 0)
{
url = "http://" + url;
}
task = WFTaskFactory::create_http_task(url, REDIRECT_MAX, RETRY_MAX,
wget_callback);
protocol::HttpRequest *req = task->get_req();
req->add_header_pair("Accept", "*/*");
req->add_header_pair("User-Agent", "Wget/1.14 (linux-gnu)");
req->add_header_pair("Connection", "close");
task->start();
wait_group.wait();
return 0;
}
1、waitgroup.done,在后面等待http结束
2、解析并处理输入的url
3、创造task,入参是url、最大重定向数、最大retry数量、入参是task的callback
4、task请求url
5、callback函数开始真正执行:http请求-》拿到response、state-》通过cursor来遍历req、response
-》从response中拿到body-》通过fwrite写到stdout-》fflush(stdout)
缺点
感觉这个库太古老,还用到了fwrite、fflush这种需要记忆的知识,现在这个时代为啥不用C++11之后的库呢?