实现简易HTTP服务器

简介: 实现简易HTTP服务器

一、套接字接口类封装


#include<iostream>
#include<string>
#include<vector>
#include<unistd.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/socket.h>
//封装TCPsocket类
#define MAX_LISTEN 5
#define CHECK_RETURN(X) if((X) == false) {return -1;}
class TCPsocket {
  private:
    int _sockfd;
  public:
    TCPsocket () : _sockfd(-1) {}
    //1.创建套接字
    bool Socket() {
      _sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
      if (_sockfd < 0) {
        perror("create socket error!");
        return false;
      }
      return true;
    } 
    //2.为套接字绑定地址信息
    bool Bind(const std::string &ip, uint16_t port) {
      struct sockaddr_in addr;
      addr.sin_family = AF_INET;
      addr.sin_port = htons(port);
      addr.sin_addr.s_addr = inet_addr(ip.c_str());
      socklen_t len = sizeof(struct sockaddr_in);
      int ret = bind(_sockfd, (struct sockaddr*)&addr, len);
      if (ret < 0) {
        perror("bind error!");
        return false;
      }
      return true;
    }
    //客户端:3.向服务器发起连接请求
    bool Connect(const std::string &ip, uint16_t port) {
      struct sockaddr_in addr;
      addr.sin_family = AF_INET;
      addr.sin_port = htons(port);
      addr.sin_addr.s_addr = inet_addr(ip.c_str());
      socklen_t len = sizeof(struct sockaddr_in);
      int ret = connect(_sockfd, (struct sockaddr*)&addr, len);
      if (ret < 0) {
        perror("connect error!");
        return false;
      }
      return true;
    }
    //服务端:3.开始监听
    bool Listen(int backlog = MAX_LISTEN) {
      int ret = listen(_sockfd, backlog);
      if (ret < 0) {
        perror("connect error!");
        return false;
      }
      return true;
    }
    //服务端:4. 获取新建连接
    bool Accept(TCPsocket *sock, std::string *ip = NULL, uint16_t *port = NULL) {
      struct sockaddr_in addr;
      socklen_t len = sizeof(struct sockaddr_in);
      int newfd = accept(_sockfd, (struct sockaddr*)&addr, &len);
      if (newfd < 0) {
        perror("accept error!");
        return false;
      }
      sock -> _sockfd = newfd;
      if (ip != NULL) *ip = inet_ntoa(addr.sin_addr);
      if (port != NULL) *port = ntohs(addr.sin_port);
      return true;
    }
    //4. 接收数据
    bool Recve(std::string *body) {
      char temp[8193] = {0};
      int ret = recv(_sockfd, temp, 8192, 0);
      if (ret < 0) {
        perror("recve error!");
        return false;
      }
      else if (ret == 0) {
        std::cout<<"peer shutdown!"<< std::endl;
        return false;
      }
      body -> assign(temp, ret);
      return true;
    }
    //5.发送数据
    bool Send(const std::string &body) {
      int ret = send(_sockfd, body.c_str(), body.size(), 0);
      if (ret < 0) {
        perror("send error!");
        return false;
      }
      return true;
    }
    //6.关闭套接字
    bool Close() {
      if (_sockfd != -1) close(_sockfd);
      return true;
    }
};


二、服务器实现


#include "socket_tcp.hpp"
#include <sstream>
int main(int argc, char *argv[]) {
  if (argc != 2) {
    std::cout<<"./http_server  port"<< std::endl;
    return -1;
  }
  int srv_port = std::stoi(argv[1]);
  std::string srv_ip = "0.0.0.0";
  TCPsocket sock;
  //1.创建套接字
  CHECK_RETURN(sock.Socket());
  //2.绑定地址信息
  CHECK_RETURN(sock.Bind(srv_ip, srv_port));
  //3.开始监听
  CHECK_RETURN(sock.Listen());
  while(1) {
    TCPsocket new_sock;
    bool ret = sock.Accept(&new_sock);
    //4.获取新建连接
    if (ret == false) continue;
    //5.收发数据
    std::string rec;
    new_sock.Recve(&rec);
    size_t pos = rec.find("\r\n\r\n");//查找头部结尾标志
    if (pos == std::string::npos) {
      //没有找到,则认为头部过大
      //将响应状态码设置为414
      //这里简单实现,就直接错误返回了
      return -1;
    }
    std::string header = rec.substr(0,pos);//截取头部
    std::string body = rec.substr(pos + 4);//截取正文
    //正常的截图正文,应该将头部按照\r\n进行分割,逐个取出头部;
    //然后根据头部中的Content-Length确定正文长度,正文长度= rec.size() - header.size() - 4;
    //然后在截取正文
    std::cout<<"header:[" << body << "]" << std::endl;
    std::cout<< "body:[" << body << "]" << std::endl;
    //响应
    std::string rep_body = "<html><body><h1>Hello world!</h1></body></html>";
    std::stringstream ss_reply;
    ss_reply << "HTTP/1.1 200 OK\r\n";
    ss_reply << "Connection: close\r\n";
    ss_reply << "Content-Type: text/html\r\n";
    ss_reply << "Content-Length: " << rep_body.size() << "\r\n";
    ss_reply << "\r\n";
    ss_reply << rep_body;
    std::cout << "response:[" << ss_reply.str() << "]" << std::endl;
    new_sock.Send(ss_reply.str());
    //短连接,完成响应,关闭连接
    new_sock.Close();
  }
  //6.关闭套接字
  sock.Close();
  return 0;
}


三、实现效果


1.运行服务端


1.png


2.在浏览器输入URL进行请求获取响应


 image.png


相关文章
|
6月前
|
C# 图形学 开发者
Unity开发中使用UnityWebRequest从HTTP服务器下载资源。
总之,UnityWebRequest就是游戏开发者手中的万能钓鱼竿,既可以获取文本数据,也能钓上图片资源,甚至是那声音的涟漪。使用UnityWebRequest的时候,你需要精心准备,比如确定URL、配置请求类型和头信息;发起请求;巧妙处理钓获的数据;还需要机智面对网络波澜,处理各种可能出现的错误。按照这样的过程,数据的钓取将会是一次既轻松愉快也效率高效的编程钓鱼之旅。
289 18
|
6月前
|
应用服务中间件 网络安全 数据安全/隐私保护
网关服务器配置指南:实现自动DHCP地址分配、HTTP服务和SSH无密码登录。
哇哈哈,道具都准备好了,咱们的魔术秀就要开始了。现在,你的网关服务器已经魔法满满,自动分配IP,提供网页服务,SSH登录如入无人之境。而整个世界,只会知道效果,不会知道是你在幕后操控一切。这就是真正的数字世界魔法师,随手拈来,手到擒来。
334 14
|
5月前
|
JSON 前端开发 Go
Go语言实战:创建一个简单的 HTTP 服务器
本篇是《Go语言101实战》系列之一,讲解如何使用Go构建基础HTTP服务器。涵盖Go语言并发优势、HTTP服务搭建、路由处理、日志记录及测试方法,助你掌握高性能Web服务开发核心技能。
|
5月前
|
Go
如何在Go语言的HTTP请求中设置使用代理服务器
当使用特定的代理时,在某些情况下可能需要认证信息,认证信息可以在代理URL中提供,格式通常是:
396 0
|
7月前
|
存储 安全 数据安全/隐私保护
HFS-快速创建HTTP服务器
鉴于HFS的操作简便和方便快捷,它在满足快速,临时的文件分享和传输需求上,能够发挥出巨大的作用。只要明确了以上的安全警告,并做好了必需的安全设置,HFS将是一款实用的HTTP服务器工具。
560 9
|
Web App开发 前端开发 Java
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
线程的状态有:new、runnable、running、waiting、timed_waiting、blocked、dead 当执行new Thread(Runnabler)后,新创建出来的线程处于new状态,这种线程不可能执行 当执行thread.start()后,线程处于runnable状态,这种情况下只要得到CPU,就可以开始执行了。
860 0
|
Web App开发 前端开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
总结和计划总是让人喜悦或镇痛,一方面以前一段时间没有荒废,能给现在的行动以信心,另一方面看到一年的时间并不能完成很多事情,需要抓紧时间。
739 0
|
Web App开发 前端开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
Every Programmer Should Know These Latency Numbers 1秒=1000毫秒(ms) 1秒=1,000,000 微秒(μs) 1秒=1,000,000,000 纳秒(ns) 1秒=1,000,000,000,000 皮秒(ps) L1 cache reference .
728 0
|
Web App开发 监控 前端开发
|
Web App开发 前端开发 Linux
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
 频繁的文件访问会导致系统的Cache使用量大增   $ free -m   total used free shared buffers cached   Mem: 3955 3926 28 0 55 3459   -...
730 0

热门文章

最新文章