创建一个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请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但 ...
随机推荐
- .NET遍历二维数组-先行/先列哪个更快?
上周在.NET性能优化群里面有一个很有意思的讨论,讨论的问题如下所示: 请教大佬:2D数组,用C#先遍历行再遍历列,或者先遍历列再遍历行,两种方式在性能上有区别吗? 据我所知,Julia或者pytho ...
- Nginx09 http的keepalive及在nginx的配置使用
1 为什么要有Connection: keep-alive? 在早期的HTTP/1.0中,每次http请求都要创建一个连接,而创建连接的过程需要消耗资源和时间,为了减少资源消耗,缩短响应时间,就需要重 ...
- OPENMP FOR CONSTRUCT GUIDED 调度方式实现原理和源码分析
OPENMP FOR CONSTRUCT GUIDED 调度方式实现原理和源码分析 前言 在本篇文章当中主要给大家介绍在 OpenMP 当中 guided 调度方式的实现原理.这个调度方式其实和 dy ...
- SpringMVC的常用注解、参数绑定、转发与重定向
SpringMvc的常用注解 @RequestMapping() SpringMvc通过@RequestMapping注解将URL请求与业务的方法进行映射,在控制器的类定义处定义方法处都可以添加@Re ...
- 快学会这个技能-.NET API拦截技法
大家好,我是沙漠尽头的狼. 本文先抛出以下问题,请在文中寻找答案,可在评论区回答: 什么是API拦截? 一个方法被很多地方调用,怎么在不修改这个方法源码情况下,记录这个方法调用的前后时间? 同2,不修 ...
- golang使用JWX进行认证和加密
golang使用JWX进行认证和加密 最近看了一个名为go-auth的库,它将JWT作为HTTP cookie对用户进行验证,但这个例子中缺少了对JWT的保护,由此进行了一些针对JWX的研究. 下面描 ...
- OPTIRRA研究: TNF拮抗剂维持期优化减量方案[EULAR2015_SAT0150]
OPTIRRA研究: TNF拮抗剂维持期优化减量方案 SAT0150 OPTIMISING TREATMENT WITH TNF INHIBITORS IN RHEUMATOID ARTHRITI ...
- 解决veture和eslint冲突的问题
vscoder自带的veture和eslint存在冲突,主要表现在 末尾逗号,分号,单双引号的不一致.解决办法:1.npm install --save-dev prettier2.在根目录新建.pr ...
- 如何把已安装的nodejs高版本降级为低版本(图文教程)
第一步.先清空本地安装的node.js版本 1.按健win+R弹出窗口,键盘输入cmd,然后敲回车(或者鼠标直接点击电脑桌面最左下角的win窗口图标弹出,输入cmd再点击回车键) 2.然后进入命令控制 ...
- PostgreSQL数据库所有的等待事件
Wait Event Type Wait Event Name Description LWLock ShmemIndexLock Waiting to find or allocate space ...