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服务器就是把服务器的标准输出发送到连接上来的客户端即可。