最近因为要和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的更多相关文章

  1. 在一个空ASP.NET Web项目上创建一个ASP.NET Web API 2.0应用

    由于ASP.NET Web API具有与ASP.NET MVC类似的编程方式,再加上目前市面上专门介绍ASP.NET Web API 的书籍少之又少(我们看到的相关内容往往是某本介绍ASP.NET M ...

  2. C#中自己动手创建一个Web Server(非Socket实现)

    目录 介绍 Web Server在Web架构系统中的作用 Web Server与Web网站程序的交互 HTTPListener与Socket两种方式的差异 附带Demo源码概述 Demo效果截图 总结 ...

  3. ASP.NET Core中如何针对一个使用HttpClient对象的类编写单元测试

    原文地址: How to unit test a class that consumes an HttpClient with IHttpClientFactory in ASP.NET Core? ...

  4. SpringCloud学习6-如何创建一个服务消费者consumer

    上一节如何创建一个服务提供者provider已经启动了一个provider的server,提供用户信息查询接口.接下来,我们启动另一个provider,由于是同一台机器本地测试,我们换一个端口 --s ...

  5. 创建多线程的HttpClient

    在实际的应用中,我们的联网应用程序里应该有一个HttpClient,并将其用于所有的HTTP通信.这就可能在同一个Http Client同时发出多个请求,也就产生了多线程的问题.幸运的是,在HttpC ...

  6. 简单创建一个SpringCloud2021.0.3项目(四)

    目录 1. 项目说明 1. 版本 2. 用到组件 3. 功能 2. 上三篇教程 3. 日志处理 1. 创建日志公共模块 2. Eureka引入日志模块 4. 到此的功能代码 5. 注册中心换成naco ...

  7. 简单创建一个SpringCloud2021.0.3项目(三)

    目录 1. 项目说明 1. 版本 2. 用到组件 3. 功能 2. 上俩篇教程 3. Gateway集成sentinel,网关层做熔断降级 1. 超时熔断降级 2. 异常熔断 3. 集成sentine ...

  8. 用html5的canvas和JavaScript创建一个绘图程序

    本文将引导你使用canvas和JavaScript创建一个简单的绘图程序. 创建canvas元素 首先准备容器Canvas元素,接下来所有的事情都会在JavaScript里面. <canvas ...

  9. 搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 (1)

    搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 原文地址(英文):http://www.networkcomms.net/creating ...

  10. ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程

    从<ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求>我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但 ...

随机推荐

  1. 数字游戏(NOIP 2003 PJT2)

    一 原始数据处理 1.输入数据得到a[1]~a[n],复制扩展a[n+1]~a[2*n],以便处理不同点为起点出发. cin>>n>>m; for(int i=1;i<= ...

  2. 3分钟教你安装 Dropzone4 文件拖拽增强工具 中文破解版 亲测有效

    Dropzone下载 下载直通车:立即下载 安装教程 打开我给你提供的Dropzone4 安装包 鼠标选中第一个程序拖到第二个程序里 在启动台打开 会出现下面情况 不要慌 点击好  去访达找到对应的软 ...

  3. java2022.7.9

    知识点

  4. Vue 注册全局组件的方式

    一.语法:Vue的实例.component("组件名称",组件) 1.方式一:这个组件就是 vue文件 import { createApp,h } from 'vue' //引入 ...

  5. C语言小程序-天天酷跑类游戏 26号完成

    1.创建游戏内背景 2.实现人物 奔跑 跳跃 优化帧 3.障碍物 出现 https://kxd.lanzoul.com/iKXU20elmtah 开源地址 半成品

  6. 记一次 .NET 某医保平台 CPU 爆高分析

    一:背景 1. 讲故事 一直在追这个系列的朋友应该能感受到,我给这个行业中无数的陌生人分析过各种dump,终于在上周有位老同学找到我,还是个大妹子,必须有求必应 . 妹子公司的系统最近在某次升级之后, ...

  7. 修改安卓ID为硬件唯一ID

    前言: 最近接到个需求,我们新产品上的外包侧APP需要使用硬件唯一ID(不管怎么升级怎么操作,ID始终不变和硬件绑定),用来做权限校验. 由于了解到安卓ID或序列号都会在擦除升级后重新随机生成,所以这 ...

  8. 有趣的python库-tkinter

    tkinter-GUI编程用 与pyqt.wxpython一样,python三大gui库之一,用来写图形化界面很有意思,下面举个整蛊小例子. 实现烦人的弹窗 import tkinter as tk, ...

  9. MySQL错误锦集【持续更新】

    [42000][1075] Incorrect table definition; there can be only one auto column and it must be defined a ...

  10. 抗TNF治疗改变JIA患者PBMC基因表达谱,可预测疗效

    抗TNF治疗改变JIA患者PBMC基因表达谱,可预测疗效 Moorthy LN, et al. ACR 2007. Presentation No:1713. 背景:我们假设儿童期发生的特发性关节炎( ...