栏目分类:
子分类:
返回
文库吧用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
文库吧 > IT > 软件开发 > 后端开发 > C/C++/C#

【Web开发】C++实现Web服务器(libevent,libcurl)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Web开发】C++实现Web服务器(libevent,libcurl)

Web服务器系列相关文章编写如下:

  1. 【Web开发】Node.js实现Web服务器(http模块)
  2. 【Web开发】Node.js实现Web服务器(express模块)
  3. 【Web开发】Python实现Web服务器(Flask入门)
  4. 【Web开发】Python实现Web服务器(Flask测试)
  5. 【Web开发】Python实现Web服务器(Tornado入门)
  6. 【Web开发】Python实现Web服务器(Tornado+flask+nginx)
  7. 【Web开发】Python实现Web服务器(FastAPI)
  8. 【Web开发】Android手机上基于Termux实现Web服务器(Python、node.js)
  9. 【Web开发】C++实现Web服务器(libevent,libcurl)

文章目录
  • 1、简介
    • 1.1 libevent
    • 1.2 libcurl
    • 1.3 openssl
    • 1.4 cJSON
  • 2、libevent
    • 2.1 下载
    • 2.2 VS2017编译
    • 2.3 VS2008编译
    • 2.4 代码测试(http服务端)
    • 2.5 代码测试(http客户端)
  • 3、libcurl
    • 3.1 下载
    • 3.2 编译
    • 3.3 代码测试(http客户端)
    • 3.4 命令行
  • 结语

1、简介 1.1 libevent

官网地址:
https://libevent.org/

libevent - 一个事件通知库。

目前,libevent支持 /dev/poll、 kqueue(2)、 event ports、 POSIX select(2)、 Windows select()、 poll(2)和epoll(4)。内部事件机制完全独立于暴露的事件 API,简单更新 libevent 即可提供新功能,而无需重新设计应用程序。结果,Libevent允许可移植的应用程序开发,并提供操作系统上可用的最具可扩展性的事件通知机制。Libevent 也可以用于多线程应用程序,通过隔离每个 event_base 以便只有单个线程访问它,或者通过锁定对单个共享 event_base 的访问。 Libevent应该在 Linux、*BSD、Mac OS X、Solaris、Windows 等上编译。

Libevent 还为缓冲网络 IO 提供了一个复杂的框架,支持套接字、过滤器、速率限制、SSL、零拷贝文件传输和 IOCP。Libevent 包括对几个有用协议的支持,包括 DNS、HTTP 和最小的 RPC 框架。

1.2 libcurl

官网地址:
https://curl.se/libcurl/

libcurl - 多协议文件传输库.

libcurl 是一个免费且易于使用的客户端 URL 传输库,支持 DICT、FILE、FTP、FTPS、GOPHER、GOPHERS、HTTP、HTTPS、IMAP、IMAPS、LDAP、LDAPS、MQTT、POP3、POP3S、RTMP、 RTMPS、RTSP、SCP、SFTP、SMB、SMBS、SMTP、SMTPS、TELNET 和 TFTP。libcurl 支持 SSL 证书、HTTP POST、HTTP PUT、FTP 上传、基于 HTTP 表单的上传、代理、HTTP/2、HTTP/3、cookies、用户+密码认证(Basic、Digest、NTLM、Negotiate、Kerberos)、文件传输恢复,http代理隧道等等!

libcurl 是高度可移植的,它可以在多种平台上构建和工作,包括 Solaris、NetBSD、FreeBSD、OpenBSD、Darwin、HPUX、IRIX、AIX、Tru64、Linux、UnixWare、HURD、Windows、Amiga、OS/2、BeOs、Mac OS X、Ultrix、QNX、OpenVMS、RISC OS、Novell NetWare、DOS 等…

libcurl 是免费的、线程安全的、与 IPv6 兼容、功能丰富、支持良好、速度快、文档完整,并且已被许多知名、大型和成功的公司使用。

1.3 openssl

详细介绍请查看本人另外一篇文章:
https://blog.csdn.net/hhy321/article/details/125922276

1.4 cJSON

cJSON是一个使用C语言编写的JSON数据解析器,具有超轻便,可移植,单文件的特点,使用MIT开源协议。
https://github.com/DaveGamble/cJSON

  • 从git下载源代码
  • 源代码文件夹如下:
mkdir build
cd build
cmake ..
# or
cmake .. -DENABLE_CJSON_UTILS=On -DENABLE_CJSON_TEST=Off

  • 生成的工程文件如下:
  • 举例说明:
    这里有一个json字符串如下:
{
    "name": "Awesome 4K",
    "resolutions": [
        {
            "width": 1280,
            "height": 720
        },
        {
            "width": 1920,
            "height": 1080
        },
        {
            "width": 3840,
            "height": 2160
        }
    ]
}
  • 通过cJSON代码构建上面的json字符串如下:
//create a monitor with a list of supported resolutions
//NOTE: Returns a heap allocated string, you are required to free it after use.
char *create_monitor(void)
{
    const unsigned int resolution_numbers[3][2] = {
        {1280, 720},
        {1920, 1080},
        {3840, 2160}
    };
    char *string = NULL;
    cJSON *name = NULL;
    cJSON *resolutions = NULL;
    cJSON *resolution = NULL;
    cJSON *width = NULL;
    cJSON *height = NULL;
    size_t index = 0;

    cJSON *monitor = cJSON_CreateObject();
    if (monitor == NULL)
    {
        goto end;
    }

    name = cJSON_CreateString("Awesome 4K");
    if (name == NULL)
    {
        goto end;
    }
    
    cJSON_AddItemToObject(monitor, "name", name);

    resolutions = cJSON_CreateArray();
    if (resolutions == NULL)
    {
        goto end;
    }
    cJSON_AddItemToObject(monitor, "resolutions", resolutions);

    for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index)
    {
        resolution = cJSON_CreateObject();
        if (resolution == NULL)
        {
            goto end;
        }
        cJSON_AddItemToArray(resolutions, resolution);

        width = cJSON_CreateNumber(resolution_numbers[index][0]);
        if (width == NULL)
        {
            goto end;
        }
        cJSON_AddItemToObject(resolution, "width", width);

        height = cJSON_CreateNumber(resolution_numbers[index][1]);
        if (height == NULL)
        {
            goto end;
        }
        cJSON_AddItemToObject(resolution, "height", height);
    }

    string = cJSON_Print(monitor);
    if (string == NULL)
    {
        fprintf(stderr, "Failed to print monitor.n");
    }

end:
    cJSON_Delete(monitor);
    return string;
}
  • 通过cJSON代码解析上面的json字符串如下:
int supports_full_hd(const char * const monitor)
{
    const cJSON *resolution = NULL;
    const cJSON *resolutions = NULL;
    const cJSON *name = NULL;
    int status = 0;
    cJSON *monitor_json = cJSON_Parse(monitor);
    if (monitor_json == NULL)
    {
        const char *error_ptr = cJSON_GetErrorPtr();
        if (error_ptr != NULL)
        {
            fprintf(stderr, "Error before: %sn", error_ptr);
        }
        status = 0;
        goto end;
    }

    name = cJSON_GetObjectItemCaseSensitive(monitor_json, "name");
    if (cJSON_IsString(name) && (name->valuestring != NULL))
    {
        printf("Checking monitor "%s"n", name->valuestring);
    }

    resolutions = cJSON_GetObjectItemCaseSensitive(monitor_json, "resolutions");
    cJSON_ArrayForEach(resolution, resolutions)
    {
        cJSON *width = cJSON_GetObjectItemCaseSensitive(resolution, "width");
        cJSON *height = cJSON_GetObjectItemCaseSensitive(resolution, "height");

        if (!cJSON_IsNumber(width) || !cJSON_IsNumber(height))
        {
            status = 0;
            goto end;
        }

        if ((width->valuedouble == 1920) && (height->valuedouble == 1080))
        {
            status = 1;
            goto end;
        }
    }

end:
    cJSON_Delete(monitor_json);
    return status;
}
  • 再举例说明如下:
{
    name: "tomcat",
    age: "21",
    city: "beijing"
}
cJSON *root = cJSON_CreateObject();

cJSON_AddStringToObject(root, "name", "tomcat");
cJSON_AddStringToObject(root, "age", "21");
cJSON_AddStringToObject(root, "city", "beijing");

char* str_json = cJSON_Print(root);
printf("构建:%sn", str_json);

cJSON_Delete(root);
root = NULL;


cJSON *root2;
root2 = cJSON_Parse(str_json);
cJSON *result = cJSON_GetObjectItem(root2, "name");
if(result) printf("解析name:%sn", result->valuestring);
result = cJSON_GetObjectItem(root2, "age");
if (result) printf("解析age:%sn", result->valuestring);
result = cJSON_GetObjectItem(root2, "city");
if (result) printf("解析city:%sn", result->valuestring);

2、libevent 2.1 下载

https://github.com/libevent/libevent

2.2 VS2017编译

采用最新的版本2.1.12-stable。

2.3 VS2008编译

采用比较早期版本,比如2.0.22-stable。

  • makefile.nmake
# WATCH OUT!  This makefile is a work in progress.  It is probably missing
# tons of important things.  DO NOT RELY ON IT TO BUILD A GOOD LIBEVENT.

# Needed for correctness
CFLAGS=/IWIN32-Code /Iinclude /Icompat /DWIN32 /DHAVE_CONFIG_H /I.

# For optimization and warnings
CFLAGS=$(CFLAGS) /Ox /W3 /wd4996 /nologo

# XXXX have a debug mode

LIBFLAGS=/nologo

CORE_OBJS=event.obj buffer.obj bufferevent.obj bufferevent_sock.obj 
	bufferevent_pair.obj listener.obj evmap.obj log.obj evutil.obj 
	strlcpy.obj signal.obj bufferevent_filter.obj evthread.obj 
	bufferevent_ratelim.obj evutil_rand.obj
WIN_OBJS=win32select.obj evthread_win32.obj buffer_iocp.obj 
	event_iocp.obj bufferevent_async.obj
EXTRA_OBJS=event_tagging.obj http.obj evdns.obj evrpc.obj

ALL_OBJS=$(CORE_OBJS) $(WIN_OBJS) $(EXTRA_OBJS)
STATIC_LIBS=libevent_core.lib libevent_extras.lib libevent.lib


all: static_libs tests

static_libs: $(STATIC_LIBS)

libevent_core.lib: $(CORE_OBJS) $(WIN_OBJS)
	lib $(LIBFLAGS) $(CORE_OBJS) $(WIN_OBJS) /out:libevent_core.lib 

libevent_extras.lib: $(EXTRA_OBJS)
	lib $(LIBFLAGS) $(EXTRA_OBJS) /out:libevent_extras.lib

libevent.lib: $(CORE_OBJS) $(WIN_OBJS) $(EXTRA_OBJS)
	lib $(LIBFLAGS) $(CORE_OBJS) $(EXTRA_OBJS) $(WIN_OBJS) /out:libevent.lib

clean:
	del $(ALL_OBJS)
	del $(STATIC_LIBS)
	cd test
	$(MAKE) /F Makefile.nmake clean

tests:
	cd test
	$(MAKE) /F Makefile.nmake

cd C:UserstomcatDesktoplibevent-2.0.22-stable.tarlibevent-2.0.22-stable
nmake Makefile.nmake



考虑到lib文件区分有md、mdd、mt、mtd所以我们在编译前,修改makefile.nmake文件:

CFLAGS=$(CFLAGS) /Ox /MD /W3 /wd4996 /nologo
CFLAGS=$(CFLAGS) /Ox /MDD /W3 /wd4996 /nologo
CFLAGS=$(CFLAGS) /Ox /MT /W3 /wd4996 /nologo
CFLAGS=$(CFLAGS) /Ox /MTD /W3 /wd4996 /nologo
nmake /f makefile.nmake clean
nmake /f makefile.nmake static_libs
2.4 代码测试(http服务端)
#include 
#include 
#include 

#pragma comment(lib, "libevent\libevent.lib")
#pragma comment(lib, "libevent\libevent_core.lib")
#pragma comment(lib, "libevent\libevent_extras.lib")





 
#include "../util-internal.h"

#include 
#include 
#include 

#include 
#include 

#ifdef WIN32
#include 
#include 
#include 
#include 
#include 
#ifndef S_ISDIR
#define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
#endif
#else
#include 
#include 
#include 
#include 
#include 
#include 
#endif

#include 
#include 
#include 
#include 
#include 

#ifdef _EVENT_HAVE_NETINET_IN_H
#include 
# ifdef _XOPEN_SOURCE_EXTENDED
#  include 
# endif
#endif


#include "../util-internal.h"

#ifdef WIN32
//#define stat _stat
//#define fstat _fstat
//#define open _open
//#define close _close
//#define O_RDONLY _O_RDONLY
#endif

char uri_root[512];

static const struct table_entry {
	const char *extension;
	const char *content_type;
} content_type_table[] = {
	{ "txt", "text/plain" },
	{ "c", "text/plain" },
	{ "h", "text/plain" },
	{ "html", "text/html" },
	{ "htm", "text/htm" },
	{ "css", "text/css" },
	{ "gif", "image/gif" },
	{ "jpg", "image/jpeg" },
	{ "jpeg", "image/jpeg" },
	{ "png", "image/png" },
	{ "pdf", "application/pdf" },
	{ "ps", "application/postsript" },
	{ NULL, NULL },
};

int from_hex(char ch)
{
	return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
}

std::string UrlUnescapeString(const std::string& s)
{
	std::istringstream ss(s);
	std::string result;
	std::getline(ss, result, '%');
	std::string buffer;
	while (std::getline(ss, buffer, '%'))
	{
		if (buffer.size() >= 2)
		{
			result += char((from_hex(buffer[0]) << 4) | from_hex(buffer[1])) + buffer.substr(2);
		}
	}
	return result;
}


static const char *
guess_content_type(const char *path)
{
	const char *last_period, *extension;
	const struct table_entry *ent;
	last_period = strrchr(path, '.');
	if (!last_period || strchr(last_period, '/'))
		goto not_found; 
	extension = last_period + 1;
	for (ent = &content_type_table[0]; ent->extension; ++ent) {
		if (!evutil_ascii_strcasecmp(ent->extension, extension))
			return ent->content_type;
	}

not_found:
	return "application/misc";
}


static void
dump_request_cb(struct evhttp_request *req, void *arg)
{
	const char *cmdtype;
	struct evkeyvalq *headers;
	struct evkeyval *header;
	struct evbuffer *buf;

	switch (evhttp_request_get_command(req)) {
	case EVHTTP_REQ_GET: cmdtype = "GET"; break;
	case EVHTTP_REQ_POST: cmdtype = "POST"; break;
	case EVHTTP_REQ_HEAD: cmdtype = "HEAD"; break;
	case EVHTTP_REQ_PUT: cmdtype = "PUT"; break;
	case EVHTTP_REQ_DELETE: cmdtype = "DELETE"; break;
	case EVHTTP_REQ_OPTIONS: cmdtype = "OPTIONS"; break;
	case EVHTTP_REQ_TRACE: cmdtype = "TRACE"; break;
	case EVHTTP_REQ_CONNECT: cmdtype = "CONNECT"; break;
	case EVHTTP_REQ_PATCH: cmdtype = "PATCH"; break;
	default: cmdtype = "unknown"; break;
	}

	printf("Received a %s request for %snHeaders:n",
	    cmdtype, evhttp_request_get_uri(req));

	headers = evhttp_request_get_input_headers(req);
	for (header = headers->tqh_first; header;
	    header = header->next.tqe_next) {
		printf("  %s: %sn", header->key, header->value);
	}

	buf = evhttp_request_get_input_buffer(req);
	puts("Input data: <<<");
	while (evbuffer_get_length(buf)) {
		int n;
		char cbuf[128];
		n = evbuffer_remove(buf, cbuf, sizeof(cbuf));
		if (n > 0)
			(void) fwrite(cbuf, 1, n, stdout);
	}
	puts(">>>");

	evhttp_send_reply(req, 200, "OK", NULL);
}



sPluginNotify m_notify;
sHttpParam mParam;

static void
send_document_cb(struct evhttp_request *req, void *arg)
{
	struct evbuffer *evb = NULL;
	const char *docroot = (const char *)arg;
	const char *uri = evhttp_request_get_uri(req);
	struct evhttp_uri *decoded = NULL;
	const char *path;
	char *decoded_path;
	char *whole_path = NULL;
	size_t len;
	int fd = -1;
	struct stat st;

	if (evhttp_request_get_command(req) != EVHTTP_REQ_GET) {
		dump_request_cb(req, arg);
		return;
	}
	if (uri == NULL) {
		return;
	}

	printf("Got a GET request for <%s>n", uri);
	if (strstr(uri, "favicon.ico")) {
		return;
	}

	
	decoded = evhttp_uri_parse(uri);
	if (!decoded) {
		printf("It's not a good URI. Sending BADREQUESTn");
		evhttp_send_error(req, HTTP_BADREQUEST, 0);
		return;
	}

	std::string uri_ansi = UrlUnescapeString(uri);
	FxLib::Type::CUtf8Buffer str_utf8(uri_ansi.c_str());
	uri = str_utf8.Get();

	
	path = evhttp_uri_get_path(decoded);
	if (!path) path = "/";

	
	decoded_path = evhttp_uridecode(path, 0, NULL);
	if (decoded_path == NULL)
		goto err;
	
	if (strstr(decoded_path, ".."))
		goto err;

	
	evb = evbuffer_new();
	/
	const char* name_prefix = strstr(uri, "name=");
	if (name_prefix == NULL) {
		goto err;
	}
	printf("client: %sn", uri);

	evhttp_add_header(evhttp_request_get_output_headers(req),
		"Content-Type", "text/html;charset=gb2312");
		
	evbuffer_add_printf(evb, "n");
	if(uri != NULL) evbuffer_add_printf(evb, uri);
	if (name_prefix && name_prefix + 5 != NULL) {
		evbuffer_add_printf(evb, "
n"); evbuffer_add_printf(evb, name_prefix + 5); } evbuffer_add_printf(evb, "n"); evhttp_send_reply(req, 200, "OK", evb); / goto done; err: evhttp_send_error(req, 404, "Document was not found"); if (fd>=0) close(fd); done: if (decoded) evhttp_uri_free(decoded); if (decoded_path) free(decoded_path); if (whole_path) free(whole_path); if (evb) evbuffer_free(evb); } static void syntax(void) { fprintf(stdout, "Syntax: http-server n"); } DWORD WINAPI https_createServer(LPVOID lpParam) { struct event_base *base; struct evhttp *http; struct evhttp_bound_socket *handle; // unsigned short port = (unsigned short)lpParam; if(port == 0) { std::string dllPath = "C:\Config\"; if (!::PathFileExists(dllPath.c_str())) { ::CreateDirectory(dllPath.c_str(), NULL); port = 5050; } else { std::string iniPath = dllPath; iniPath += "server.ini"; std::ifstream ifs(iniPath.c_str(), std::ifstream::in); std::string line; std::getline(ifs, line); if (line.size() > 5) { port = atoi(line.substr(5).c_str()); } ifs.close(); } } // #ifdef WIN32 WSADATA WSAData; WSAStartup(0x101, &WSAData); #else if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) return (1); #endif base = event_base_new(); if (!base) { fprintf(stderr, "Couldn't create an event_base: exitingn"); return 1; } http = evhttp_new(base); if (!http) { fprintf(stderr, "couldn't create evhttp. Exiting.n"); return 1; } evhttp_set_cb(http, "/dump", dump_request_cb, NULL); evhttp_set_gencb(http, send_document_cb, "c://"); handle = evhttp_bind_socket_with_handle(http, "0.0.0.0", port); if (!handle) { fprintf(stderr, "couldn't bind to port %d. Exiting.n", (int)port); return 1; } { struct sockaddr_storage ss; evutil_socket_t fd; ev_socklen_t socklen = sizeof(ss); char addrbuf[128]; void *inaddr; const char *addr; int got_port = -1; fd = evhttp_bound_socket_get_fd(handle); memset(&ss, 0, sizeof(ss)); if (getsockname(fd, (struct sockaddr *)&ss, &socklen)) { perror("getsockname() failed"); return 1; } if (ss.ss_family == AF_INET) { got_port = ntohs(((struct sockaddr_in*)&ss)->sin_port); inaddr = &((struct sockaddr_in*)&ss)->sin_addr; } else if (ss.ss_family == AF_INET6) { got_port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port); inaddr = &((struct sockaddr_in6*)&ss)->sin6_addr; } else { fprintf(stderr, "Weird address family %dn", ss.ss_family); return 1; } addr = evutil_inet_ntop(ss.ss_family, inaddr, addrbuf, sizeof(addrbuf)); if (addr) { printf("Listening on %s:%dn", addr, got_port); evutil_snprintf(uri_root, sizeof(uri_root), "http://%s:%d",addr,got_port); } else { fprintf(stderr, "evutil_inet_ntop failedn"); return 1; } } event_base_dispatch(base); return 0; } void main() { https_createServer(5000); }
2.5 代码测试(http客户端)
#include "StdAfx.h"
#include "FxHttpClient.h"
#include 
#include 
#include 

#include "event2/http.h"
#include "event2/http_struct.h"
#include "event2/event.h"
#include "event2/buffer.h"
#include "event2/dns.h"
#include "event2/thread.h"

#include 
#include 
#include 
#include 
#include 

void RemoteReadCallback(struct evhttp_request* remote_rsp, void* arg)
{
	event_base_loopexit((struct event_base*)arg, NULL);
}

void ReadChunkCallback(struct evhttp_request* remote_rsp, void* arg)
{
	char buf[4096];
	struct evbuffer* evbuf = evhttp_request_get_input_buffer(remote_rsp);
	int n = 0;
	while ((n = evbuffer_remove(evbuf, buf, 4096)) > 0)
	{
		fwrite(buf, n, 1, stdout);
	}
}

void RemoteConnectionCloseCallback(struct evhttp_connection* connection, void* arg)
{
	fprintf(stderr, "remote connection closedn");
	event_base_loopexit((struct event_base*)arg, NULL);
}

DWORD_PTR https_createClient(const char* dwUrl)
{
	const char* url = (const char*)dwUrl;
	if(dwUrl == NULL) url = "http://127.0.0.1:5000/hello";
	std::string strUrl = url;

	std::string dllPath = "C:\Config\";
	if (!::PathFileExists(dllPath.c_str())) {
		::CreateDirectory(dllPath.c_str(), NULL);
	}
	else if (*url == '#'){
		std::string iniPath = dllPath;
		iniPath += "client.ini";
		std::ifstream ifs(iniPath.c_str(), std::ifstream::in);
		if (!ifs || ifs.is_open() == false){  
			std::cout << "fail to open the file" << std::endl;  
			return -1;
		}else{ 
			std::cout << "open the file successfully" << std::endl;
		}

		std::string line;
		std::string cmdName = "cmd";
		cmdName += (url+1);
		
		while (std::getline(ifs, line)) {
			const char* line_ptr = line.c_str();
			if(strstr(line_ptr, cmdName.c_str()) == line_ptr) {
				int pos = line.find("=") + 1;
				std::string line_text = line.substr(pos);
				strUrl = line_text.c_str();
				break;
			}
		}
		ifs.close();
	}
	url = strUrl.c_str();

	struct evhttp_uri* uri = evhttp_uri_parse(url);
	if (!uri)
	{
		fprintf(stderr, "parse url failed!n");
		return 1;
	}

	struct event_base* base = event_base_new();
	if (!base)
	{
		fprintf(stderr, "create event base failed!n");
		return 1;
	}

	struct evdns_base* dnsbase = evdns_base_new(base, 1);
	if (!dnsbase)
	{
		fprintf(stderr, "create dns base failed!n");
	}
	assert(dnsbase);

	struct evhttp_request* request = evhttp_request_new(RemoteReadCallback, base);
	//evhttp_request_set_header_cb(request, ReadHeaderDoneCallback);
	evhttp_request_set_chunked_cb(request, ReadChunkCallback);
	//evhttp_request_set_error_cb(request, RemoteRequestErrorCallback);

	const char* host = evhttp_uri_get_host(uri);
	if (!host)
	{
		fprintf(stderr, "parse host failed!n");
		return 1;
	}

	int port = evhttp_uri_get_port(uri);
	if (port < 0) port = 80;

	const char* request_url = url;
	const char* path = evhttp_uri_get_path(uri);
	if (path == NULL || strlen(path) == 0)
	{
		request_url = "/";
	}

	printf("url:%s host:%s port:%d path:%s request_url:%sn", url, host, port, path, request_url);

	struct evhttp_connection* connection = evhttp_connection_base_new(base, dnsbase, host, port);
	if (!connection)
	{
		fprintf(stderr, "create evhttp connection failed!n");
		return 1;
	}

	evhttp_connection_set_closecb(connection, RemoteConnectionCloseCallback, base);

	evhttp_add_header(evhttp_request_get_output_headers(request), "Host", host);
	evhttp_make_request(connection, request, EVHTTP_REQ_GET, request_url);

	event_base_dispatch(base);

	return 0;
}

void main()
{
	https_createClient("http://127.0.0.1:5000/hello");
}
3、libcurl 3.1 下载

https://curl.se/download.html

3.2 编译

解压上面下载的源代码压缩包如下:





3.3 代码测试(http客户端)
#include 
#include 

int main(void)
{
  CURL *curl;
  CURLcode res;

  
  curl_global_init(CURL_GLOBAL_ALL);

  
  curl = curl_easy_init();
  if(curl) {
    
    curl_easy_setopt(curl, CURLOPT_URL, "http://127.0.0.1/login");
    
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "username=test");

    
    res = curl_easy_perform(curl);
    
    if(res != CURLE_OK)
      fprintf(stderr, "curl_easy_perform() failed: %sn",
              curl_easy_strerror(res));

    
    curl_easy_cleanup(curl);
  }
  curl_global_cleanup();
  return 0;
}
3.4 命令行
  • 输出帮助信息
curl --help

  • GET 请求
curl https://www.baidu.com/         # GET请求, 输出 响应内容
curl -I https://www.baidu.com/      # GET请求, 只输出 响应头
curl -i https://www.baidu.com/      # GET请求, 输出 响应头、响应内容
curl -v https://www.baidu.com/      # GET请求, 输出 通讯过程、头部信息、响应内容等
curl https://www.baidu.com -o baidu.txt  #下载文件
curl https://www.baidu.com/index.html -O #下载文件
#下载文件
curl -A "Mozilla/5.0 Chrome/70.0.3538.110 Safari/537.36" 
     -e "https://www.baidu.com/" 
     https://www.baidu.com/index.html -O

  • POST 请求
# POST 提交 JSON 数据
curl -H "Content-Type: application/json"                
     -d '{"name":"test", "type":"100"}'     
     http://localhost/login
 
# POST 提交 表单数据
curl -F "name=test"                
     -F "type=100"               
     http://localhost/login
结语

如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;(✿◡‿◡)
感谢各位大佬童鞋们的支持!( ´ ▽´ )ノ ( ´ ▽´)っ!!!

转载请注明:文章转载自 www.wk8.com.cn
本文地址:https://www.wk8.com.cn/it/1038804.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 wk8.com.cn

ICP备案号:晋ICP备2021003244-6号