创建一个httpserver、httpclient
最近因为要和java进行通信、约定好使用http协议进行消息传递。在网上找了很久server编写发现有个博主写的很详细,因此把东西记录下来以便下次使用。这是原博主网址:https://blog.csdn.net/h593245631/article/details/94033451
1、httpserver创建
1)httpserver.cpp
#include "httpserver.h"
#include <thread>
#include <regex> #include "utils.h"
#include "TransactionApi.h" using namespace std; HttpServer::HttpServer() {
//初始化winsock2.2相关的动态库
WSADATA wd; // 获取socket相关信息
if (0 != WSAStartup(MAKEWORD(2, 2), &wd)) { //0 表示成功
cout << "WSAStartup error: " << WSAGetLastError() << endl;
return;
}
cout << "WSAStartup success: " << endl;
} HttpServer::~HttpServer() {
//清理winsock2的环境
WSACleanup();
} bool HttpServer::start(unsigned short port) {
_isExit = false;
_port = port;
if (!init()) {
cout << "httpserver start error" << endl;
} thread sth(&HttpServer::run, this);
sth.detach(); cout << "httpserver start success" << endl;
return true;
} void HttpServer::run() {
//主线程循环接收客户端的链接
while (!_isExit) {
sockaddr_in addrClient;
int len = sizeof(sockaddr_in); //4. 接收成功返回与client通讯的socket
SOCKET c = accept(_listenSocket, (SOCKADDR*)&addrClient, &len);
if (INVALID_SOCKET != c) {
//创建线程 并且传入与client通讯的套接字
thread sth(&HttpServer::clientThreadFun, this, (LPVOID)c);
//thread sth(&HttpServer::clientThreadFun, this);
sth.detach();
}
}
} DWORD WINAPI HttpServer::clientThreadFun(LPVOID lpThreadParameter) {
//5. 与客户端通讯 发送或者接收数据
SOCKET c = (SOCKET)lpThreadParameter; //循环接收客户端数据
int ret = 0;
int cun =0;
string connect;
do {
char buf[1024 * 2] = { 0 }; ret = recv(c, buf, sizeof(buf) - 1, 0); if (ret <= 0) {
break;
}
buf[ret] = '\0';
cout << "客户端" << c << "请求信息 : " << buf << endl; if (!getRequest(buf)) {
break;
} //string respStr = getResponse(to_string(cun));
string respStr = getResponse("testok");
ret = send(c, respStr.c_str(), respStr.size(), 0);
cout << "客户端" << c << "请求应答信息 : " << respStr << endl;
break; } while (ret != SOCKET_ERROR && ret != 0); closesocket(c);
return 0;
} bool HttpServer::init() { //1. 创建TCP socket 流式套接字
_listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_HOPOPTS);
if (INVALID_SOCKET == _listenSocket) {
cout << "socket error :" << WSAGetLastError() << endl;
return false;
} //2. 绑定socket到一个IP地址和端口
sockaddr_in addr; //不建议使用sockaddr 建议用sockaddr_in
addr.sin_family = AF_INET; // 地址族
addr.sin_port = htons(_port);//本地端口 转网络字节序
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);//ip地址转网络字节序 int len = sizeof(sockaddr_in);
if (SOCKET_ERROR == ::bind(_listenSocket, (sockaddr*)&addr, len)) {
cout << "bind error: " << WSAGetLastError() << endl;
return false;
} //3. 监听, 5 代表正在等待完成相应的TCP三次握手过程的队列长度
if (SOCKET_ERROR == listen(_listenSocket, 1000)) { // 根据电脑配置设定链接数
cout << "listen error:" << WSAGetLastError() << endl;
return false;
} cout << "create listen success :" << endl;
cout << "init htttpserver success :" << endl;
return true;
} void HttpServer::stop() {
_isExit = true;
//关闭监听套接字
closesocket(_listenSocket);
} //---- bool HttpServer::getRequest(string requestStr) {
string src = requestStr; string pattern = "^([A-Z]+) /([a-zA-Z0-9]*([.][a-zA-Z]*)?)[?]?(.*) HTTP/1"; //
regex r(pattern);
smatch mas;
regex_search(src, mas, r);
if (mas.size() == 0) {
cout << pattern.c_str() << " failed!" << endl;
return false;
}
string type = mas[1];
string path = "/";
path += mas[2]; //根据path 区别请求的命令 比如 "/login" 登录
FunName =mas[2];
string filetype = mas[3];
string queryStr = mas[4]; if (type != "GET" && type != "POST") {
cout << "Not GET and POST!\n" << endl;
return false;
} //query id=1&name=xcj
vector<string> querys;
splitStr(queryStr, querys, "&"); return true;
} std::string HttpServer::getResponse(string connect) {
//回应http GET请求
//消息头
string rmsg = "";
rmsg = "HTTP/1.1 200 OK\r\n";
rmsg += "Server: xHttp\r\n";
rmsg += "Content-Type: text/html;charset=utf-8\r\n";
rmsg += "Content-Length: ";
rmsg += to_string(connect.size());
//rmsg += connect;
rmsg += "\r\n";
rmsg += "\r\n\r\n";
rmsg += connect;
return rmsg;
}
2)httpserver.h
#pragma once
#pragma once #include <WinSock2.h>
#include <WS2tcpip.h>
#include <iostream> using namespace std; #pragma comment(lib, "Ws2_32.lib") class HttpServer {
public:
HttpServer();
~HttpServer(); bool start(unsigned short port);
void run();
void stop();
string FunName;
private:
bool init();
//线程函数 处理客户端来的请求
DWORD WINAPI clientThreadFun(LPVOID lpThreadParameter); bool _isExit = false;
unsigned short _port = 8892; //端口号
SOCKET _listenSocket = INVALID_SOCKET; //监听套接字 //处理http消息
bool getRequest(string str);
std::string getResponse(string connectLen); };
3)utils.cpp
#include "utils.h" void splitStr(const string& s, vector<string>& v, const string& c) {
string::size_type pos1, pos2;
pos2 = s.find(c);
pos1 = 0;
while (string::npos != pos2) {
v.push_back(s.substr(pos1, pos2 - pos1)); pos1 = pos2 + c.size();
pos2 = s.find(c, pos1);
}
if (pos1 != s.length())
v.push_back(s.substr(pos1));
}
4)utils.h
#include <vector>
#include <string>
#include <iostream> using namespace std; void splitStr(const string& s, vector<string>& v, const string& c);
5)main
#include "httpserver.h"
#include <WinSock.h>
#include <iostream>
#include <Windows.h> int main(int argc, char* argv[]) { unsigned short port = 8888;
HttpServer server;
server.start(port); getchar();
}
本次程序是使用vs2019进行编译运行,配置的ip是127.0.0.1端口8888。
2、httpclient创建
1)httpclient.cpp
#include "httpclient.h"
#include <WinSock.h>
#include <iostream>
#include <Windows.h> #pragma comment(lib, "ws2_32.lib") HttpRequest::HttpRequest(const std::string& ip, int port) : m_ip(ip), m_port(port)
{
} HttpRequest::~HttpRequest(void)
{
} // Http GET请求
std::string HttpRequest::HttpGet(std::string req)
{
std::string ret = ""; // 返回Http Response
try
{
// 开始进行socket初始化
WSADATA wData;
::WSAStartup(MAKEWORD(2, 2), &wData); SOCKET clientSocket = socket(AF_INET, 1, 0);
struct sockaddr_in ServerAddr = {0};
ServerAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
ServerAddr.sin_port = htons(8892);
ServerAddr.sin_family = AF_INET;
int errNo = connect(clientSocket, (sockaddr*)&ServerAddr, sizeof(ServerAddr));
if(errNo == 0)
{
// "GET /[req] HTTP/1.1\r\n"
// "Connection:Keep-Alive\r\n"
// "Accept-Encoding:gzip, deflate\r\n"
// "Accept-Language:zh-CN,en,*\r\n"
// "User-Agent:Mozilla/5.0\r\n\r\n";
std::string strSend = " HTTP/1.1\r\n"
"Cookie:16888\r\n\r\n";
strSend = "GET " + req + strSend; // 发送
errNo = send(clientSocket, strSend.c_str(), strSend.length(), 0);
if(errNo > 0)
{
//cout << "发送成功" << endl;
}
else
{
std::cout << "errNo:" << errNo << std::endl;
return ret;
} // 接收
char bufRecv[3069] = {0};
errNo = recv(clientSocket, bufRecv, 3069, 0);
if(errNo > 0)
{
ret = bufRecv;// 如果接收成功,则返回接收的数据内容
}
else
{
std::cout << "errNo:" << errNo << std::endl;
return ret;
}
}
else
{
errNo = WSAGetLastError();
std::cout << "errNo:" << errNo << std::endl;
}
// socket环境清理
::WSACleanup();
}
catch (...)
{
return "";
}
return ret;
} // Http POST请求
std::string HttpRequest::HttpPost(std::string req, std::string data)
{
std::string ret = ""; // 返回Http Response
try
{
// 开始进行socket初始化;
WSADATA wData;
::WSAStartup(MAKEWORD(2, 2), &wData); SOCKET clientSocket = socket(AF_INET, 1, 0);
struct sockaddr_in ServerAddr = {0};
ServerAddr.sin_addr.s_addr = inet_addr(m_ip.c_str());
ServerAddr.sin_port = htons(m_port);
ServerAddr.sin_family = AF_INET;
int errNo = connect(clientSocket, (sockaddr*)&ServerAddr, sizeof(ServerAddr));
if(errNo == 0)
{
// 格式化data长度
char len[10] = {0};
sprintf(len, "%d", data.length());
std::string strLen = len; // "POST /[req] HTTP/1.1\r\n"
// "Connection:Keep-Alive\r\n"
// "Accept-Encoding:gzip, deflate\r\n"
// "Accept-Language:zh-CN,en,*\r\n"
// "Content-Length:[len]\r\n"
// "Content-Type:application/x-www-form-urlencoded; charset=UTF-8\r\n"
// "User-Agent:Mozilla/5.0\r\n\r\n"
// "[data]\r\n\r\n";
std::string strSend = " HTTP/1.1\r\n"
"Cookie:16888\r\n"
"Content-Type:application/x-www-form-urlencoded\r\n"
"Charset:utf-8\r\n"
"Content-Length:";
strSend = "POST " + req + strSend + strLen + "\r\n\r\n" + data; // 发送
errNo = send(clientSocket, strSend.c_str(), strSend.length(), 0);
if(errNo > 0)
{
//cout<<"发送成功\n";
}
else
{
std::cout << "errNo:" << errNo << std::endl;
return ret;
} // 接收
char bufRecv[3069] = {0};
errNo = recv(clientSocket, bufRecv, 3069, 0);
if(errNo > 0)
{
ret = bufRecv;// 如果接收成功,则返回接收的数据内容
}
else
{
std::cout << "errNo:" << errNo << std::endl;
return ret;
}
}
else
{
errNo = WSAGetLastError();
}
// socket环境清理
::WSACleanup();
}
catch (...)
{
return "";
}
return ret;
} // 合成JSON字符串
std::string HttpRequest::genJsonString(std::string key, int value)
{
char buf[128] = {0};
sprintf(buf, "{\"%s\":%d}", key.c_str(), value);
std::string ret = buf;
return ret;
} // 分割字符串
std::vector<std::string> HttpRequest::split(const std::string &s, const std::string &seperator)
{
std::vector<std::string> result;
typedef std::string::size_type string_size;
string_size i = 0; while(i != s.size()){
// 找到字符串中首个不等于分隔符的字母
int flag = 0;
while(i != s.size() && flag == 0){
flag = 1;
for(string_size x = 0; x < seperator.size(); ++x)
if(s[i] == seperator[x]){
++i;
flag = 0;
break;
}
} // 找到又一个分隔符,将两个分隔符之间的字符串取出
flag = 0;
string_size j = i;
while(j != s.size() && flag == 0){
for(string_size x = 0; x < seperator.size(); ++x)
if(s[j] == seperator[x]){
flag = 1;
break;
}
if(flag == 0)
++j;
}
if(i != j){
result.push_back(s.substr(i, j-i));
i = j;
}
}
return result;
} // 从Response中查找key对应的Header的内容
std::string HttpRequest::getHeader(std::string respose, std::string key)
{
std::vector<std::string> lines = split(respose, "\r\n");
for (int i = 0; i < lines.size(); i++)
{
std::vector<std::string> line = split(lines[i], ": ");// 注意空格
if (line.size() >= 2 && line[0] == key)
{
return line[1];
}
}
return "";
}
2)httpclient.h
#pragma once
#include <string>
#include <vector> class HttpRequest
{
public:
HttpRequest(const std::string& ip, int port);
~HttpRequest(void); // Http GET请求
std::string HttpGet(std::string req); // Http POST请求
std::string HttpPost(std::string req, std::string data); // 合成JSON字符串
static std::string genJsonString(std::string key, int value); // 分割字符串
static std::vector<std::string> split(const std::string &s, const std::string &seperator); // 根据key从Response获取Header中的内容
static std::string getHeader(std::string respose, std::string key); private:
std::string m_ip = "127.0.0.1";
int m_port=8892;
};
当ip127.0.0.1port8892服务器起好时将可以连接到服务器进行消息发送和接受应答结果。
创建一个httpserver、httpclient的更多相关文章
- 在一个空ASP.NET Web项目上创建一个ASP.NET Web API 2.0应用
由于ASP.NET Web API具有与ASP.NET MVC类似的编程方式,再加上目前市面上专门介绍ASP.NET Web API 的书籍少之又少(我们看到的相关内容往往是某本介绍ASP.NET M ...
- C#中自己动手创建一个Web Server(非Socket实现)
目录 介绍 Web Server在Web架构系统中的作用 Web Server与Web网站程序的交互 HTTPListener与Socket两种方式的差异 附带Demo源码概述 Demo效果截图 总结 ...
- ASP.NET Core中如何针对一个使用HttpClient对象的类编写单元测试
原文地址: How to unit test a class that consumes an HttpClient with IHttpClientFactory in ASP.NET Core? ...
- SpringCloud学习6-如何创建一个服务消费者consumer
上一节如何创建一个服务提供者provider已经启动了一个provider的server,提供用户信息查询接口.接下来,我们启动另一个provider,由于是同一台机器本地测试,我们换一个端口 --s ...
- 创建多线程的HttpClient
在实际的应用中,我们的联网应用程序里应该有一个HttpClient,并将其用于所有的HTTP通信.这就可能在同一个Http Client同时发出多个请求,也就产生了多线程的问题.幸运的是,在HttpC ...
- 简单创建一个SpringCloud2021.0.3项目(四)
目录 1. 项目说明 1. 版本 2. 用到组件 3. 功能 2. 上三篇教程 3. 日志处理 1. 创建日志公共模块 2. Eureka引入日志模块 4. 到此的功能代码 5. 注册中心换成naco ...
- 简单创建一个SpringCloud2021.0.3项目(三)
目录 1. 项目说明 1. 版本 2. 用到组件 3. 功能 2. 上俩篇教程 3. Gateway集成sentinel,网关层做熔断降级 1. 超时熔断降级 2. 异常熔断 3. 集成sentine ...
- 用html5的canvas和JavaScript创建一个绘图程序
本文将引导你使用canvas和JavaScript创建一个简单的绘图程序. 创建canvas元素 首先准备容器Canvas元素,接下来所有的事情都会在JavaScript里面. <canvas ...
- 搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 (1)
搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 原文地址(英文):http://www.networkcomms.net/creating ...
- ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程
从<ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求>我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但 ...
随机推荐
- Nginx 安装perl
1 安装包下载 https://www.cpan.org/src获取最新偶数版本下载链接并替换(偶数版本为稳定版) 2 上传到服务器解压 tar -zxvf perl-5.36.0.tar.gz 3 ...
- Vue的介绍
目录 Vue介绍 一.前端发展史 二.Vue介绍 1.Vue是什么? 2.M-V-VM 架构思想 3.组件化开发.单页面应用 4.版本问题 三.第一个helloworld 1.了解开发前端的编辑器 2 ...
- Jpbc哈希函数如何实现
1.(0,1)→Element元素 在Jpbc库中存在两个方法 Element A=G1.newRandomElement();A.setFromBytes(arr,0,arr.length);//A ...
- 多重背包问题 II
有 NN 种物品和一个容量是 VV 的背包. 第 ii 种物品最多有 sisi 件,每件体积是 vivi,价值是 wiwi. 求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大.输 ...
- 三年观察揭示TNF抑制剂持续改善强柱患者躯体功能的预测因子
标签:强直性脊柱炎; TNF抑制剂; 躯体功能; 预测因子 一项为期3年的观察研究揭示TNF抑制剂持续改善强直性脊柱炎患者躯体功能的预测因子 电邮发布日期:2016年3月28日 文献出处: van W ...
- STM32L431 移植 LiteOS 时 _ebss _Min_Heap_Size _Min_Stack_Size 未找到或未定义
将 LiteOS 移植完成之后,编译报如下错误: 环境 版本 Keil V5.37.0.0 Windows11 2022/12/22 ARM::CMSIS 5.9(2022-05-22) 开发板 ST ...
- 01#Web 实战:雷达图
成品演示 绘制雷达图 雷达图里外层 function calcPolygonX(radarX, radius, increaseAngle) { return radarX + radius * Ma ...
- 【C++复习】同名函数判断条件(重载,隐藏,覆盖)
1.重载 以下条件要全部满足: 函数名相同 以下条件满足其1: 函数形参数目不同 函数形参类型不同 注意: 不看返回值 调用形式要不同 //下面两个函数不能重载 fun(int a,int b){} ...
- Vscode报错: error:0308010C:digital envelope routines::unsupported错误记录解决
Vscode报错: error:0308010C:digital envelope routines::unsupported错误记录解决 因为安装了新版本的node才报的错误:node版本: v18 ...
- 如何设置QGraphicsItem线宽不随QGraphicsView缩放而变小或变大
很简单,只需要重写一下Item中的paint()方法 void my_line_item::paint(QPainter *painter, const QStyleOptionGraphicsIte ...