cgi简单服务器

CGI 是Web 服务器运行时外部程序的规范,按CGI 编写的程序可以扩展服务器功能。
CGI(Common Gateway Interface) 是WWW技术中最重要的技术之一,有着不可替代的重要地位。CGI是外部应用程序(CGI程序)与WEB服务器之间的接口标准,是在CGI程序和Web服务器之间传递信息的过程。
CGI规范允许Web服务器执行外部程序,并将它们的输出发送给Web浏览器,CGI将Web的一组简单的静态超媒体文档变成一个完整的新的交互式媒体。

CGI的处理步骤:

  1. 通过Internet把用户请求送到web服务器。
  2. web服务器接收用户请求并交给CGI程序处理。
  3. CGI程序把处理结果传送给web服务器。
  4. web服务器把结果送回到用户。
    示例代码如下:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/stat.h>

#include "processpool.h"

// 用于处理客户cgi请求的类,他可以作为processpool类的模板参数
class cgi_conn {
 public:
  cgi_conn(){};
  ~cgi_conn(){};
  // 初始化客户连接,清空读缓冲区
  void init(int epollfd, int sockfd, const sockaddr_in& client_addr) {
    m_epollfd = epollfd;
    m_sockfd = sockfd;
    m_address = client_addr;
    memset(m_buf, '\0', BUFFER_SIZE);
    m_read_idx = 0;
  }

  void process() {
    int idx = 0;
    int ret = -1;
    // 循环读取和分析客户数据
    while (true) {
      idx = m_read_idx;
      ret = recv(m_sockfd, m_buf + idx, BUFFER_SIZE - 1 - idx, 0);
      // 如果读操作发生错误,则关闭客户连接,如果是暂时无数据可读,则退出循环
      if (ret < 0) {
        if (errno != EAGAIN) {
          removefd(m_epollfd, m_sockfd);
        }
        break;
      } else if (ret == 0) {
        // 如果对方关闭连接,服务器也关闭连接
        removefd(m_epollfd, m_sockfd);
        break;
      } else {
        m_read_idx += ret;
        printf("user content is: %s\n", m_buf);
        for (; idx < m_read_idx; ++idx) {
          if ((idx >= 1) && (m_buf[idx - 1] == '\r') && (m_buf[idx] == '\n')) {
            break;
          }
        }
        // 如果没有遇到字符\r\n 则需要读取更多客户数据
        if (idx == m_read_idx) {
          continue;
        }
        m_buf[idx - 1] = '\0';

        char* filename = m_buf;
        // 判断客户要运行的cgi程序是否存在
        if (access(filename, F_OK) == -1) {
          removefd(m_epollfd, m_sockfd);
          break;
        }
        // 创建子进程来执行cgi程序
        ret = fork();
        if (ret == -1) {
          removefd(m_epollfd, m_sockfd);
          break;
        } else if (ret > 0) { // 父进程
          // 父进程只需要关闭连接
          removefd(m_epollfd, m_sockfd);
          break;
        } else {
          // 子进程需要将标准输出定向到 m_sockfd,并执行cgi程序
          close(STDOUT_FILENO);
          dup(m_sockfd); // 把m_sockfd重定向到标准输出
          execl(m_buf, m_buf, 0);
          exit(0);
        }
      } // 读数据end
    } // while end

  } // process end

 private:
  static const int BUFFER_SIZE = 1024;
  static int m_epollfd;
  int m_sockfd;
  sockaddr_in m_address;
  char m_buf[BUFFER_SIZE];
  int m_read_idx; // 读的光标位置
};

int cgi_conn::m_epollfd = -1;

int main(int argc, char* argv[]) {
  if (argc <= 2) {
    printf("usage: %s ip_address port_number\n", basename(argv[0]));
    return 1;
  }
  const char* ip = argv[1];
  int port = atoi(argv[2]);

  int listenfd = socket(PF_INET, SOCK_STREAM, 0);
  assert(listenfd >= 0);

  int ret = 0;
  struct sockaddr_in address;
  bzero(&address, sizeof(address));
  address.sin_family = AF_INET;
  inet_pton(AF_INET, ip, &address.sin_addr);
  address.sin_port = htons(port);

  ret = bind(listenfd, (struct sockaddr*)&address, sizeof(address));
  assert(ret != -1);

  ret = listen(listenfd, 5);
  assert(ret != -1);

  processpool<cgi_conn>* pool = processpool<cgi_conn>::create(listenfd); // 创建唯一进程池实例
  if (pool) {
    pool->run();
    delete pool;
  }
  close(listenfd); // 正如前文提到的,main函数创建了文件描述符listenfd,那么就由它亲自关闭之

  return 0;
}

本程序需要配合上一节的线程池头文件processpool.h。
运行结果如下:

服务器

在这里插入图片描述

客户端:

在这里插入图片描述
这里只是简单模拟,由于服务器是将信息作为文件名去访问服务器文件,而客户端随意发送信息,所以判断信息不存在就直接退出了。

reference:linux高性能服务器编程——游双

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值