0
点赞
收藏
分享

微信扫一扫

Oracle 使用PLSQL 导出 一个表的insert 语句

juneyale 03-26 14:31 阅读 2

目录

1. HTTP协议

2. 认识URL

2.1. URL中的四个主要字段

2.2. URL Encode && URL Decode

3. HTTP 协议格式

3.1. 快速构建 HTTP 请求和响应的报文格式

3.1.1. HTTP 请求格式

3.1.2. HTTP 响应格式

3.1.3. 关于 HTTP 请求 && 响应的宏观理解

3.2. 实现一个 HTTP demo

3.2.1. Sock.hpp

3.2.2. Log.hpp

3.2.3. Usage.hpp  

3.2.4. HttpServer.hpp

3.2.5. HttpServer.cc (看一看 Http 请求格式)

3.2.6. HttpServer.cc (添加 HTTP 响应数据)

3.3. 通过该 demo 逐步分析过程,理解细节

3.3.1. Tool.hpp

3.3.2. HttpServer.cc (获得HTTP请求的资源路径)

3.3.3. HttpServer.cc (处理资源路径,包含默认首页) 

3.3.4. index.html 

3.3.5. error.html 

3.3.6. 简单总结


1. HTTP协议

2. 认识URL

2.1. URL中的四个主要字段

2.2. URL Encode && URL Decode

3. HTTP 协议格式

3.1. 快速构建 HTTP 请求和响应的报文格式

3.1.1. HTTP 请求格式

3.1.2. HTTP 响应格式

3.1.3. 关于 HTTP 请求 && 响应的宏观理解

3.2. 实现一个 HTTP demo

3.2.1. Sock.hpp

#ifndef __SOCK_HPP_
#define __SOCK_HPP_

#include <iostream>
#include <cstring>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#include "Log.hpp"


namespace Xq
{
  class Sock
  {
  public:
    Sock() :_sock(-1) {}

    // 创建套接字
    void Socket(void) 
    {
      _sock = socket(AF_INET, SOCK_STREAM, 0);
      if(_sock == -1)
      {
        LogMessage(FATAL, "%s,%d\n", strerror(errno));
        exit(1);
      }
      LogMessage(DEBUG, "listen sock: %d create success\n", _sock);
    }

    //  将该套接字与传入的地址信息绑定到一起
    void Bind(const std::string& ip, uint16_t port)
    {
      sockaddr_in addr;
      addr.sin_family = AF_INET;
      addr.sin_port = htons(port);
      addr.sin_addr.s_addr = ip.empty() ? INADDR_ANY : inet_addr(ip.c_str());

      int ret = bind(_sock, reinterpret_cast<const struct sockaddr*>(&addr), sizeof(addr));
      if(ret == -1)
      {
        LogMessage(FATAL, "bind error\n");
        exit(2);
      }
    }

    // 封装listen 将该套接字设置为监听状态
    void Listen(void)
    {
      int ret = listen(_sock, 10);
      if(ret == -1)
      {
        LogMessage(FATAL, "listen error\n");
        exit(3);
      }
    }

    //封装accept
    // 如果想获得客户端地址信息
    // 那么我们可以用输出型参数
    // 同时我们需要将服务套接字返回给上层
    int Accept(std::string& client_ip, uint16_t* port)
    {
      struct sockaddr_in client_addr;
      socklen_t addrlen = sizeof client_addr;
      bzero(&client_addr, addrlen);

      int server_sock = accept(_sock, \
          reinterpret_cast<struct sockaddr*>(&client_addr), &addrlen);
      if(server_sock == -1)
      {
        LogMessage(FATAL, "%s,%d\n", strerror(errno));
        return -1;
      }
      // 将网络字节序的整数转为主机序列的字符串
      client_ip = inet_ntoa(client_addr.sin_addr);
      // 网络字节序 -> 主机字节序
      *port = ntohs(client_addr.sin_port);
      // 返回服务套接字
      return server_sock;
    }

    //  向特定服务端发起连接
    void Connect(struct sockaddr_in* addr, const socklen_t* addrlen)
    {
      int ret = connect(_sock,\
          reinterpret_cast<struct sockaddr*>(addr), \
          *addrlen);
      if(ret == -1)
      {
        LogMessage(FATAL, "%s%d\n", strerror(errno));
      }
    }

    // 服务端结束时, 释放监听套接字
    ~Sock(void)
    {
      if(_sock != -1)
      {
        close(_sock);
        LogMessage(DEBUG, "close listen sock: %d\n", _sock);
      }
    }

  public:
    int _sock; // 套接字
  };
}

#endif

3.2.2. Log.hpp

#pragma once

#include "Date.hpp"
#include <iostream>
#include <map>
#include <string>
#include <cstdarg>

#define LOG_SIZE 1024

// 日志等级
enum Level
{
  DEBUG, // DEBUG信息
  NORMAL,  // 正常
  WARNING, // 警告
  ERROR, // 错误
  FATAL // 致命
};

const char* pathname = "./log.txt";

void LogMessage(int level, const char* format, ...)
{
// 如果想打印DUBUG信息, 那么需要定义DUBUG_SHOW (命令行定义, -D)
#ifndef DEBUG_SHOW
  if(level == DEBUG)
    return ;
#endif
  std::map<int, std::string> level_map;
  level_map[0] = "DEBUG";
  level_map[1] = "NORAML";
  level_map[2] = "WARNING";
  level_map[3] = "ERROR";
  level_map[4] = "FATAL";

  std::string info;
  va_list ap;
  va_start(ap, format);

  char stdbuffer[LOG_SIZE] = {0};  // 标准部分 (日志等级、日期、时间)
  snprintf(stdbuffer, LOG_SIZE, "[%s],[%s],[%s] ", level_map[level].c_str(), Xq::Date().get_date().c_str(),  Xq::Time().get_time().c_str());
  info += stdbuffer;

  char logbuffer[LOG_SIZE] = {0}; // 用户自定义部分
  vsnprintf(logbuffer, LOG_SIZE, format, ap);
  info += logbuffer;

  FILE* fp = fopen(pathname, "a");
  fprintf(fp, "%s", info.c_str());
  fclose(fp);
  va_end(ap);
}

3.2.3. Usage.hpp  

#pragma once
#include <iostream>

void Usage(const std::string &name)
{
  std::cout << "Usage:\n  "  << name <<  " port" << std::endl;
}

3.2.4. HttpServer.hpp

#ifndef _HTTPSERVER_HPP_
#define _HTTPSERVER_HPP_

#include <functional>

#include "Sock.hpp"
#include "Log.hpp"
#include "Date.hpp"
#include "Usage.hpp"

using func_t = std::function<void(int)>;

namespace Xq
{
  class HttpServer
  {
  public:
    // 初始化服务器
    HttpServer(uint16_t port)
    {
      // 创建套接字
      _sock.Socket();
      // 绑定套接字
      _sock.Bind("", port);
      // 将该套接字设置为监听状态
      _sock.Listen();
    }
    
    // 服务端需要绑定的服务
    void BindHandle(func_t func)
    {
      _func = func;
    }
    
    // 子进程执行的服务 (该服务就是外部绑定的服务)
    void ExecuteHandle(int server_sock)
    {
      _func(server_sock);
    }
    
    // 启动服务器
    void start(void)
    {
      while(true)
      {
        std::string client_ip;
        uint16_t client_port = 0;
        int server_sock = _sock.Accept(client_ip, &client_port);

        // 让子进程执行该客户端请求
        if(fork() == 0)
        {
          // 子进程关闭监听套接字
          close(_sock._sock);
          // 处理该客户端请求
          ExecuteHandle(server_sock);
          // 执行完, 关闭该服务套接字
          close(server_sock);
          // 子进程退出
          exit(0);
        }

        // 父进程不需要该服务套接字, 关闭掉
        close(server_sock);
        // 同时, 我们显式忽略了SIGCHLD信号
        // 避免僵尸问题的产生
        // 父进程继续去获取客户端连接
      }
    }

  private:
    Sock _sock;
    func_t _func;
  };
}

#endif

3.2.5. HttpServer.cc (看一看 Http 请求格式)

#include <memory>
#include <signal.h>
#include <fstream>
#include "HttpServer.hpp"
#include "Tool.hpp"

#define BUFFER_SIZE 10240

void HttpServerHandle(int sock)
{
  // 因为http底层是tcp协议
  // 而tcp协议是面向字节流的
  // 因此可以使用 recv 接口
  char buffer[BUFFER_SIZE] = {0};
  // 读取客户端请求
  ssize_t real_size = recv(sock, buffer, BUFFER_SIZE - 1, 0);
  if(real_size > 0)
  {
    buffer[real_size] = 0;
    // 打印一下 HTTP 请求
    std::cout << buffer << "------------------" << std::endl;
  }
}

int main(int arg, char** argv)
{
  if(arg != 2)
  {
    Usage(argv[0]);
    exit(1);
  }
  
  // 显示忽略 SIGCHLD 信号, 避免僵尸问题
  signal(SIGCHLD, SIG_IGN);

  std::unique_ptr<Xq::HttpServer> server(new Xq::HttpServer(atoi(argv[1])));

  // Bind 处理客户端请求的方法
  server->BindHandle(HttpServerHandle);
  // 启动服务器
  server->start();

  return 0;
}

3.2.6. HttpServer.cc (添加 HTTP 响应数据)

void HttpServerHandle(int sock)
{
  // 因为http底层是tcp协议
  // 而tcp协议是面向字节流的
  // 因此可以使用 recv 接口
  char buffer[BUFFER_SIZE] = {0};
  ssize_t real_size = recv(sock, buffer, BUFFER_SIZE - 1, 0);
  if(real_size > 0)
  {
    buffer[real_size] = 0;
    // 打印一下 HTTP 请求
    std::cout << buffer << "------------------" << std::endl;
  }

  // 状态行(服务器端HTTP版本 状态码 状态码描述符\r\n)
  std::string HttpResponse = "HTTP/1.1 200 OK\r\n";
  // 暂时不添加响应报头
  
  // 添加空行
  HttpResponse += "\r\n";
  // 响应正文 (简单的构建一个html)
  HttpResponse += "<html><h3> hello world!  </h3></html>";

  // 发送给客户端
  send(sock, HttpResponse.c_str(), HttpResponse.size(), 0);
}

int main(int arg, char** argv)
{
    // 省略
}

3.3. 通过该 demo 逐步分析过程,理解细节

 

3.3.1. Tool.hpp

#ifndef _UTIL_HPP_
#define _UTIL_HPP_

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

namespace Xq
{

  class Tool
  {
  public:
    static void CutString(const std::string& src, const std::string& sep, std::vector<std::string>* out)
    {
      size_t start = 0;
      size_t pos = 0;
      while(pos != std::string::npos && start < src.size() - 1)
      {
        pos = src.find(sep, start);
        if(pos != std::string::npos)
        {
          out->push_back(src.substr(start, pos - start));
          start = pos;
          start += sep.size();
        }
      }
      if (start < src.size())
	  {
	      out->push_back(src.substr(start));
	  }
    }
  };
}

#endif

3.3.2. HttpServer.cc (获得HTTP请求的资源路径)

#include <memory>
#include <signal.h>
#include <fstream>
#include "HttpServer.hpp"
#include "Tool.hpp"

#define BUFFER_SIZE 10240

// 服务器资源的起始目录
#define START_PATH "./wwwroot"

void HttpServerHandle(int sock)
{
  // 因为http底层是tcp协议
  // 而tcp协议是面向字节流的
  // 因此可以使用 recv 接口
  char buffer[BUFFER_SIZE] = {0};
  ssize_t real_size = recv(sock, buffer, BUFFER_SIZE - 1, 0);
  if(real_size > 0)
  {
    buffer[real_size] = 0;
    // 打印一下 HTTP 请求
    std::cout << buffer << "------------------" << std::endl;
  }

  // 这个vector用于存储HTTP请求中的每一行信息
  std::vector<std::string> v_line;
  Xq::Tool::CutString(buffer, "\r\n", &v_line);
  
  // 因为我们需要 HTTP 请求中的 资源路径
  // 故我们实际上只需要 HTTP 请求的第一行信息 (v_line[0])
  // 即请求行, 而请求行中的第二个字段就是资源路径

  // 这个vector用于存储请求行中的每一个字段
  std::vector<std::string> v_block;
  Xq::Tool::CutString(v_line[0], " ", &v_block);
  for(const auto& vit : v_block)
  {
    std::cout << vit << std::endl;
  }

  // 而此时的v_block[1]就是HTTP请求中的资源路径
  std::string resource_path = v_block[1];
  std::cout << "resource_path: " << resource_path << std::endl;

  // 状态行(服务器端HTTP版本 状态码 状态码描述符\r\n)
  std::string HttpResponse = "HTTP/1.1 200 OK\r\n";
  // 暂时不添加响应报头
  
  // 添加空行
  HttpResponse += "\r\n";
  // 响应正文 (简单的构建一个html)
  HttpResponse += "<html><h3> hello world!  </h3></html>";

  // 发送给客户端
  send(sock, HttpResponse.c_str(), HttpResponse.size(), 0);
}

int main(int arg, char** argv)
{
  if(arg != 2)
  {
    Usage(argv[0]);
    exit(1);
  }
  
  // 显示忽略 SIGCHLD 信号, 避免僵尸问题
  signal(SIGCHLD, SIG_IGN);

  std::unique_ptr<Xq::HttpServer> server(new Xq::HttpServer(atoi(argv[1])));

  // Bind 处理客户端请求的方法
  server->BindHandle(HttpServerHandle);
  // 启动服务器
  server->start();

  return 0;
}

3.3.3. HttpServer.cc (处理资源路径,包含默认首页) 

#include <memory>
#include <signal.h>
#include <fstream>
#include "HttpServer.hpp"
#include "Tool.hpp"

#define BUFFER_SIZE 10240

// 服务器资源的起始目录
#define START_PATH "./wwwroot"

void HttpServerHandle(int sock)
{
  // 因为http底层是tcp协议
  // 而tcp协议是面向字节流的
  // 因此可以使用 recv 接口
  char buffer[BUFFER_SIZE] = {0};
  ssize_t real_size = recv(sock, buffer, BUFFER_SIZE - 1, 0);
  if(real_size > 0)
  {
    buffer[real_size] = 0;
    // 打印一下 HTTP 请求
    std::cout << buffer << "------------------" << std::endl;
  }

  // 这个vector用于存储HTTP请求中的每一行信息
  std::vector<std::string> v_line;
  Xq::Tool::CutString(buffer, "\r\n", &v_line);
  
  // 因为我们需要 HTTP 请求中的 资源路径
  // 故我们实际上只需要HTTP 请求的第一行信息
  // 即请求行, 而请求行中的第二个字段就是资源路径

  // 这个vector用于存储请求行中的每一个字段
  std::vector<std::string> v_block;
  Xq::Tool::CutString(v_line[0], " ", &v_block);
  for(const auto& vit : v_block)
  {
    std::cout << vit << std::endl;
  }

  // 而此时的v_block[1]就是HTTP请求中的资源路径
  std::string resource_path = v_block[1];
  std::cout << "resource_path: " << resource_path << std::endl;

  // 服务器要访问的目标路径
  std::string Target_path;
  Target_path = START_PATH;
  Target_path += resource_path;

  // 如果该路径是Web根目录 ("/"), 那么返回默认首页
  if(resource_path == "/")
  {
    Target_path += "index.html";
  }

  // std::cout << "Target_path: " << Target_path << std::endl;
  
  // 目标路径已经准备就绪, 现在就需要打开该文件
  std::ifstream in(Target_path.c_str());

  // HTTP 响应
  std::string HttpResponse;

  // 如果该文件不存在, 那么HTTP响应中的状态码就是404
  if(!in.is_open())
  {
    // 状态行(服务器端HTTP版本 状态码 状态码描述符\r\n)
    HttpResponse = "HTTP/1.1 404  Not Found\r\n";
    // 空行
    HttpResponse += "\r\n";
    // 错误信息文件的路径
    std::string error_path = START_PATH;
    std::string error_info;
    error_path += "/error.html";
    // 将错误信息添加到HTTP响应正文中
    std::ifstream error(error_path);
    if(error.is_open())
    {
      while(getline(error, error_info))
      {
        HttpResponse += error_info;
      }
    }
    error.close();
    // done
  }
  else
  {
    // 状态行
    HttpResponse = "HTTP/1.1 200 OK\r\n";
    // 空行
    HttpResponse += "\r\n";
    // 有效载荷
    std::string content;
    while(std::getline(in, content))
    {
      HttpResponse += content;
    }
    // done
  }

  // 读取文件完毕后, 关闭文件
  in.close();

  // 发送给客户端
  send(sock, HttpResponse.c_str(), HttpResponse.size(), 0);
}

int main(int arg, char** argv)
{
    // 忽略...
}

3.3.4. index.html 

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width">
  <title> 咸蛋超人的网站 </title>
</head>
<body>
<html><p> ------------------    北国风光, 千里冰封, 万里雪飘。             --------------------- </p><html>
<html><p> ------------------    望长城内外, 惟余莽莽; 大河上下, 顿失滔滔。  --------------------- </p><html>
<html><p> ------------------    山舞银蛇, 原驰蜡象, 欲与天公试比高。       --------------------- </p><html>
<html><p> ------------------    须晴日, 看红装素裹, 分外妖娆。             --------------------- </p><html>
<html><p> ------------------    江山如此多娇, 引无数英雄竞折腰。           --------------------- </p><html>
<html><p> ------------------    惜秦皇汉武, 略输文采; 唐宗宋祖, 稍逊风骚。 --------------------- </p><html>
<html><p> ------------------    一代天骄, 成吉思汗, 只识弯弓射大雕。       --------------------- </p><html>
<html><p> ------------------    俱往矣, 数风流人物, 还看今朝。             --------------------- </p><html>
</body>
</html>

 

3.3.5. error.html 

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width">
  <title>  咸蛋超人的网站 </title>
</head>
<body>
<h1> 404 --- Not Found </h1>
</body>
</html>

3.3.6. 简单总结

举报

相关推荐

0 条评论