C++ 通过TCP Socket实现简单Http服务器

该文介绍了如何在Windows环境下使用C++编程实现一个简单的Http服务器。主要涉及Winsock2库,包含五个文件:HttpServer.hpp、HttpServer.cpp、Utils.hpp、Utils.cpp、main.cpp。服务器能接收客户端请求,解析GET和POST命令,并返回响应。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实现一个简单的Http服务器,基于windows 平台。 总共五个文件 : HttpServer.hpp、HttpServer.cpp、Utils.hpp、Utils.cpp、main.cpp

Utils.hpp

#include <vector>
#include <string>
#include <iostream>

using namespace std;

void splitStr(const string& s, vector<string>& v, const string& c);

Utils.cpp


#include "Utils.hpp"


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));
}

HttpServer.hpp

#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();

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);

};

HttpServer.cpp



#include "HttpServer.hpp"
#include <thread>
#include <regex>

#include "Utils.hpp"

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);
			sth.detach();
		}
	}
}

DWORD WINAPI HttpServer::clientThreadFun(LPVOID lpThreadParameter) {
	//5. 与客户端通讯 发送或者接收数据
	SOCKET c = (SOCKET)lpThreadParameter;

	//循环接收客户端数据
	int ret = 0;
	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 connect = "124443656556677778cxgyushining";
		string respStr = getResponse(connect);
		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" 登录   
	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 += "\r\n";
	rmsg += "\r\n\r\n";
	rmsg += connect;
	return rmsg;
}



main.cpp


#include "HttpServer.hpp"

//客户端请求格式: string url = "http://localhost:8892/query?type=shunfeng&postid=367847964498";

int main(int argc, char* argv[]) {
	
	unsigned short port = 8892;
	HttpServer server;
	server.start(port);

	getchar();
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值