响应:
第一部分测试代码,读取请求
Makefile
bin=httpserver #生成的可执行程序
cc=g++ #编译器名称
LD_FLAGS=-std=c++11 -lpthread #-DDEBUG=1 #链接选项
src=main.cc$(bin):$(src)$(cc) -o $@ $^ $(LD_FLAGS).PHONY:clean
clean:rm -f $(bin)
1111111
main.cc
#include <iostream>
#include <string>
#include <memory>
#include "HttpServer.hpp"
static void Usage(std::string proc)
{std::cout << "Usage:\n\t" << proc << " port" << std::endl;;
}int main(int argc, char *argv[])
{if( argc != 2 ){Usage(argv[0]);exit(4);}int port = atoi(argv[1]);std::shared_ptr<HttpServer> http_server(new HttpServer(port));http_server->InitServer();http_server->Loop();return 0;
}
11111
Log.hpp
#pragma once#include <iostream>
#include <string>
#include <ctime>#define INFO 1
#define WARNING 2
#define ERROR 3
#define FATAL 4#define LOG(level, message) Log(#level, message, __FILE__, __LINE__)void Log(std::string level, std::string message, std::string file_name, int line)
{ // [日志级别][时间戳][日志信息][错误文件名称][行数]std::cout << "[" << level << "]" << "[" << time(nullptr) << "]" << "[" << message << "]" << "[" << file_name << "]" << "[" << line << "]" << std::endl;
}
111
TcpServer.hpp
#pragma once#include <iostream>
#include <cstdlib>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include "Log.hpp"#define BACKLOG 7class TcpServer
{private:int _port;int _listen_sock;static TcpServer* _svr; // 指向单例对象的static指针,懒汉模式private: // 单例模式TcpServer(int port): _port(port), _listen_sock(-1){}TcpServer(){}TcpServer(const TcpServer& s) = delete;TcpServer* operator=(const TcpServer& s) = delete;public:static TcpServer *GetInstance(int port){static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;if(nullptr == _svr){pthread_mutex_lock(&lock);if(nullptr == _svr){_svr = new TcpServer(port);_svr->InitServer();}pthread_mutex_unlock(&lock);}return _svr;}void InitServer(){Socket();Bind();Listen();LOG(INFO, "tcp_server init ... success");}void Socket(){_listen_sock = socket(AF_INET, SOCK_STREAM, 0);if(_listen_sock < 0){LOG(FATAL, "socket error");exit(1);}int opt = 1; // 端口复用:宕机了也能立马绑定端口号setsockopt(_listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));LOG(INFO, "create socket ... success");}void Bind(){struct sockaddr_in local;memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port);local.sin_addr.s_addr = INADDR_ANY; //云服务器不能直接绑定公网IPif(bind(_listen_sock, (struct sockaddr*)&local, sizeof(local)) < 0){LOG(FATAL, "bind error");exit(2);}LOG(INFO, "bind socket ... success");}void Listen(){if(listen(_listen_sock, BACKLOG) < 0){LOG(FATAL, "listen socket error");exit(3);}LOG(INFO, "listen socket ... success");}int Sock(){return _listen_sock;}~TcpServer(){if(_listen_sock >= 0){close(_listen_sock);}}
};TcpServer* TcpServer::_svr = nullptr;
11111111
HttpServer.hpp
#pragma once#include <iostream>
#include <pthread.h>
#include <signal.h>
#include "Log.hpp"
#include "TcpServer.hpp"
#include "Protocol.hpp"#define PORT 7777class HttpServer
{private:int _port;bool _stop;public:HttpServer(int port = PORT): _port(port), _stop(false){}void InitServer(){// 信号SIGPIPE进行忽略,否则在写入时候,可能直接崩溃serversignal(SIGPIPE, SIG_IGN); }void Loop(){TcpServer *tsvr = TcpServer::GetInstance(_port);LOG(INFO, "Loop begin");while(!_stop){struct sockaddr_in peer;socklen_t len = sizeof(peer);int sock = accept(tsvr->Sock(), (struct sockaddr*)&peer, &len);if(sock < 0) // 获取套接字失败{continue;}LOG(INFO, "Get a new link");int *_sock = new int(sock); // 暂时方案pthread_t pid;pthread_create(&pid, nullptr, Entrance::HandlerRequest, _sock);pthread_detach(pid);}}~HttpServer(){}
};
1111
Protocol.hpp
#pragma once#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "Log.hpp"
#include "Util.hpp"#define DEBUG
class Entrance // 线程入口
{
public:Entrance(){}~Entrance(){}static void* HandlerRequest(void * _sock){int sock = *(int*)_sock; // 临时测试方案LOG(INFO, "Hander Request Begin");
#ifdef DEBUG//For Testchar buffer[4096];recv(sock, buffer, sizeof(buffer), 0);std::cout << "-------------begin----------------" << std::endl;std::cout << buffer << std::endl;std::cout << "-------------end----------------" << std::endl;
#else EndPoint* ep = new EndPoint(sock);ep->RecvHttpRequest();ep->BuildHttpResponse();ep->SendHttpResponse();delete ep;
#endifLOG(INFO, "Hander Request End");}
};
测试结果
11111
第二部分测试代码,解析请求,返回静态网页
过程截图:
读取请求行和报头
解析uri:
返回了静态网页:
telnet测试:
加上了响应类型和长度:
第二份代码链接:
Linux_Code: 存放linux学习代码 - Gitee.com