wwwroot(目录)/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>比特就业课</title>
</head>
<body>
<h3>这是一个Linux课程</h3>
<p>我是一个Linux的学习者,我正在进行http的测试工作!!!</p>
</body>
</html>
Makefile
HttpServer:HttpServer.cc
g++ -o HttpServer HttpServer.cc -std=c++11
.PHONY:clean
clean:
rm -f HttpServer
Log.hpp
#pragma once
#include <iostream>
#include <string>
#include <cstdarg>
#include <cstdio>
#include <ctime>
#define DEBUG 0
#define NORMAL 1
#define WARNING 2
#define ERROR 3
#define FATAL 4
const char *gLevelMap[5] = {"DEBUG", "NORMAL", "WARNING", "ERROR", "FATAL"};
#define LOGFILE "./threadpool.log"
void logMessage(int level, const char *format, ...)
{
char stdBuffer[1024]; // 标准部分
time_t timestamp = time(nullptr);
struct tm *time = localtime(×tamp);
snprintf(stdBuffer, sizeof stdBuffer, "[%s][%ld]", gLevelMap[level], timestamp);
char logBuffer[1024]; // 自定义部分
va_list args;
va_start(args, format);
vsnprintf(logBuffer, sizeof(logBuffer), format, args); // 使用 vsnprintf 而不是 vsprintf
va_end(args);
//FILE* fp=fopen(LOGFILE,"a");
//打印到显示器
printf("%s %s\n", stdBuffer, logBuffer);
// 打印到指定文件
//fprintf(fp,"%s%s\n",stdBuffer,logBuffer);
//fclose(fp);
}
Sock.hpp
#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string>
#include <sys/wait.h>
#include "Log.hpp"
#include <memory>
class Sock
{
private:
const static int gbacklog = 20;
public:
Sock() {}
int Socket()
{
int listensock = socket(AF_INET, SOCK_STREAM, 0);
if (listensock < 0)
{
logMessage(FATAL, "create socket error,%d:%s", errno, strerror(errno));
exit(2);
}
logMessage(NORMAL, "create socket success, listensock: %d", listensock);
return listensock;
}
void Bind(int sock, uint16_t port, std::string ip = "0.0.0.0")
{
struct sockaddr_in local;
memset(&local, 0, sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(port);
inet_pton(AF_INET, ip.c_str(), &local.sin_addr);
// local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());
if (bind(sock, (const sockaddr *)&local, sizeof(local)) < 0)
{
logMessage(FATAL, "bind error, %d:%s", errno, strerror(errno));
exit(3);
}
}
void Listen(int sock)
{
if (listen(sock, gbacklog) < 0)
{
logMessage(FATAL, "listen error, %d:%s", errno, strerror(errno));
exit(4);
}
logMessage(NORMAL, "listen server success");
}
int Accept(int listensock, std::string *ip, uint16_t *port)
{
struct sockaddr_in src;
memset(&src, 0, sizeof(src));
socklen_t len = sizeof(src);
int servicesock = accept(listensock, (struct sockaddr *)&src, &len);
if (servicesock < 0)
{
logMessage(ERROR, "accept error,%d:%s", errno, strerror(errno));
return -1;
}
if (port)
*port = ntohs(src.sin_port);
if (ip)
*ip = inet_ntoa(src.sin_addr);
return servicesock;
}
bool Connect(int sock, const std::string &server_ip, const uint16_t &server_port)
{
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(server_port);
server.sin_addr.s_addr = inet_addr(server_ip.c_str());
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) == 0)
return true;
else
return false;
}
~Sock()
{
}
};
Usage.hpp
#pragma once
#include <iostream>
void Usage(const char *args)
{
std::cout << "\nUsage: " << args << " port" << std::endl;
}
Util.hpp
#pragma once
#include <iostream>
#include <vector>
class Util
{
public:
static void cutString(const std::string &s, const std::string &sep, std::vector<std::string> *out)
{
std::size_t start = 0;
while (start < s.size())
{
auto pos = s.find(sep, start);
if (pos == std::string::npos)
{
break;
}
std::string sub = s.substr(start, pos - start);
out->push_back(sub);
start += sub.size();
start += sep.size();
}
if (start < s.size())
out->push_back(s.substr(start));
}
};
HttpServer.hpp
#pragma once
#include <iostream>
#include "Sock.hpp"
#include <functional>
#include <unistd.h>
class HttpServer
{
public:
using func_t = std::function<void(int)>;
public:
HttpServer(uint16_t port, func_t func)
: _port(port), _func(func)
{
_listensock = sock.Socket();
sock.Bind(_listensock, _port);
sock.Listen(_listensock);
}
void Start()
{
signal(SIGCHLD, SIG_IGN);
while (true)
{
std::string clientIp;
uint16_t clientPort;
int sockfd = sock.Accept(_listensock, &clientIp, &clientPort);
if (sockfd == -1)
{
continue;
}
if (fork() == 0)
{
close(_listensock);
_func(sockfd);
close(sockfd);
exit(0);
}
close(sockfd);
}
}
~HttpServer()
{
if (_listensock >= 0)
{
close(_listensock);
}
}
private:
int _listensock;
uint16_t _port;
Sock sock;
func_t _func;
};
HttpServer.cc
#include <iostream>
#include "HttpServer.hpp"
#include <memory>
#include "Usage.hpp"
#include <unistd.h>
#include "Util.hpp"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <fstream>
#define ROOT "./wwwroot"
#define HOMEPAGE "index.html"
void HandlerHttpRequest(int sockfd)
{
// 1.读取请求
char buffer[1024];
int s = read(sockfd, buffer, sizeof buffer);
if (s > 0)
{
buffer[s] = 0;
// std::cout << buffer << "--------------------" << std::endl;
}
std::vector<std::string> vline;
Util::cutString(buffer, "\n", &vline);
std::vector<std::string> vblock;
Util::cutString(vline[0], " ", &vblock);
std::string file = vblock[1];
std::string target = ROOT;
//默认首页
if (file == "/")
file = "/index.html";
target += file;
std::cout << target << std::endl;
std::string content;
std::ifstream in(target);
if (in.is_open())
{
std::string line;
while (std::getline(in, line))
{
content += line;
}
in.close();
}
// for (auto &iter : vblock)
// {
// std::cout << iter << "\n"
// << std::endl;
// }
// 2.试着构建一个http的响应
std::string HttpResponse;
if (content.empty())
{
HttpResponse = "HTTP/1.1 404 NotFound\r\n";
}
else
HttpResponse = "HTTP/1.1 200 OK\r\n";
HttpResponse += "\r\n";
HttpResponse += content;
send(sockfd, HttpResponse.c_str(), HttpResponse.size(), 0);
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
Usage(argv[0]);
exit(0);
}
std::unique_ptr<HttpServer> httpserver(new HttpServer(atoi(argv[1]), HandlerHttpRequest));
httpserver->Start();
return 0;
}