CGI全称是“公共网关接口”(Common Gateway Interface),HTTP服务器与你的或其它机器上的程序进行“交谈”的一种工具,其程序须运行在网络服务器上。

CGI可以用任何一种语言编写,只要这种语言具有标准输入、输出和环境变量。

《Linux高性能服务器编程》(游双)一书中使用了dup系统调用实现了一个简易的CGI服务器。

#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <assert.h>
#include <poll.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>

using namespace std;

int main(int argc, char* argv[])
{
    if(argc <= 2)
    {
        cout << "usage: " << basename(argv[0]) << " ipaddress portnumber" << endl;
        return 1;
    }

    const char* ip = argv[1];
    int port = atoi(argv[2]);

    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);

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

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

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

    struct sockaddr_in client;
    socklen_t client_addrlength = sizeof(client);
    int connfd = accept(listenfd, (struct sockaddr*)&client, &client_addrlength);
    if(connfd < 0)
    {
        cout << "errno is: " << errno << endl;
    }
    else
    {
       close(STDOUT_FILENO);     //这里关闭了标准输出文件描述符1
       dup(connfd);              //dup将accept函数返回的客户套接字connfd重定向到目前最小的文件描述符1
       cout << "abcd" << endl;   //这样标准输出的“abcd”实际上就发给客户端了
       close(connfd);            //用完关闭connfd
    }


    close(listenfd);
    return 0;
}

这个简易CGI服务器的主要业务逻辑已经用注释标明。
以下是运行结果:
图片说明
我们开启另一个shell用nc命令连上它,得到了预期输出“abcd”
图片说明
综上,一个简易的CGI服务器就是把服务器的标准输出发送到连接上来的客户端即可。