Linux开发——C语言调用外部程序(如lua,python,php,java...)方法(CGI)

目录

CGI定义

CGI功能  

CGI编程

GET方法:

POST方法

实战

get方法服务端代码

get方法外部程序(c语言)例子

post方法服务器端程序

post方法外部程序(c语言)例子


CGI定义

是用于WEB服务器和外部应用之间信息交换的标准接口。物理上是一段程序。

CGI功能  

简单功能:计数器、生成包含日期、天气等的页面

中等难度的功能:图象映象、动画

高级任务:后端数据库操作、搜索引擎、多重动态页面

CGI编程

GET方法:

使用GET方法向CGI程序发送数据时,client端的数据是作为URL的一部分进行发送的。

WEB服务器通过QUERY_STRING将数据发送给相应的CGI程序。

REQUEST_METHOD为GET。

输入数据的长度有限制:由SERVER本身的buffer size决定 (一般用于同样输入产生同样结果的表单,如查询数据库)

POST方法

由标准输入将FORM表单数据传给CGI。

QUERY_STRING变量为空

传送数据的量由环境变量中的Content_length决定

REQUEST_METHOD为POST (POST方式用于每次请求都有不同结果输出的表单)

实战

服务器中的get响应cgi

1,将要get的数据(如url中的部分数据)放入到提前约定好的环境变量中

2,建立进程间通信,

3,调用第三方程序

服务器中的post响应cgi

1,创建一个子进程向当前进程输入信息(管道)

2,重定向(管道)到当前进程的标准输入

3,创建一个子进程,重定向这个子进程的标准输出到另一个通道

4,通过通道读取第二个子进程输出的内容

get方法服务端代码

void get_dynamic(int fd, char *filename, char *cgiargs) 
{
    char buf[MAXLINE], *emptylist[] = { NULL },httpsbuf[MAXLINE];
    int p[2];

    /* Return first part of HTTP response */
    sprintf(buf, "HTTP/1.0 200 OK\r\n");
    sprintf(buf, "%sServer: Tiny Web Server\r\n",buf);

    #ifdef HTTPS 
    if(ishttps)
    	SSL_write(ssl,buf,strlen(buf));
    else
    #endif
       	Rio_writen(fd, buf, strlen(buf));
	
    #ifdef HTTPS 
    if(ishttps)
    {
    	Pipe(p);//进程间通信管道
       	if (Fork() == 0)
	{  /* child  */ 
		Close(p[0]);
		setenv("QUERY_STRING", cgiargs, 1); //设置内容到环境变量
		Dup2(p[1], STDOUT_FILENO);         /* 重定向子进程管道到标准输出 */
		Execve(filename, emptylist, environ); /* 调用第三方子进程 */	
	}
	Close(p[1]);
	Read(p[0],httpsbuf,MAXLINE);   /* 父进程读取管道中的内容 */
	SSL_write(ssl,httpsbuf,strlen(httpsbuf));
    }
    else
    #endif
    {
	if (Fork() == 0) 
	{ /* child */
		/* Real server would set all CGI vars here */
		setenv("QUERY_STRING", cgiargs, 1); 
		Dup2(fd, STDOUT_FILENO);         /* Redirect stdout to client */
		Execve(filename, emptylist, environ); /* Run CGI program */
	}
    }
    //Wait(NULL); /* Parent waits for and reaps child */
}

get方法外部程序(c语言)例子

#include "wrap.h"
#include "parse.h"

int main(void) 
{
    char *buf, *p;
    char name[MAXLINE], passwd[MAXLINE],content[MAXLINE];

    /* 读取约定环境变量中的内容 */
    if ((buf = getenv("QUERY_STRING")) != NULL) {
	p = strchr(buf, '&');
	*p = '\0';
	strcpy(name, buf);
	strcpy(passwd, p+1);
    }


    /* 输入内容到重定向后的标准输出 */
    sprintf(content, "Welcome to auth.com:%s and %s\r\n<p>",name,passwd);
    sprintf(content, "%s\r\n", content);

    sprintf(content, "%sThanks for visiting!\r\n", content);
  
    printf("Content-length: %d\r\n", strlen(content));
    printf("Content-type: text/html\r\n\r\n");
    printf("%s", content);
    fflush(stdout);
    exit(0);
}

post方法服务器端程序

static void post_dynamic(int fd, char *filename, int contentLength,rio_t *rp)
{
    char buf[MAXLINE],length[32], *emptylist[] = { NULL },data[MAXLINE];
    int p[2];

    #ifdef HTTPS 
    int httpsp[2];
    #endif

    sprintf(length,"%d",contentLength);
    memset(data,0,MAXLINE);

    Pipe(p);

    /*       The post data is sended by client,we need to redirct the data to cgi stdin.
    *  	 so, child read contentLength bytes data from fp,and write to p[1];
    *    parent should redirct p[0] to stdin. As a result, the cgi script can
    *    read the post data from the stdin. 
    */

    /* 创建一个子进程向当前进程输入内容 */
   
    	if (Fork() == 0)
	{                     /* child  */ 
		Close(p[0]);
		#ifdef HTTPS 
		if(ishttps)
		{
			Write(p[1],httpspostdata,contentLength);	
		}
		else
		#endif
		{
			Rio_readnb(rp,data,contentLength);
			Rio_writen(p[1],data,contentLength);
		}
		exit(0)	;
	}
    
    /* Send response headers to client */
    sprintf(buf, "HTTP/1.0 200 OK\r\n");
    sprintf(buf, "%sServer: Tiny Web Server\r\n",buf);

    #ifdef HTTPS 
    if(ishttps)
    	SSL_write(ssl,buf,strlen(buf));
    else
    #endif
        Rio_writen(fd, buf, strlen(buf));

    //Wait(NULL);
    Dup2(p[0],STDIN_FILENO);  /* 重定向管道 p[0] 到当前进程的标准输入 */
    Close(p[0]);

    Close(p[1]);
    setenv("CONTENT-LENGTH",length , 1); 

    #ifdef HTTPS 
    if(ishttps)  /* if ishttps,we couldnot redirct stdout to client,we must use SSL_write */
    {
    	Pipe(httpsp);

	if(Fork()==0)
	{
    		Dup2(httpsp[1],STDOUT_FILENO);        /* 重定向当前进程的标准输出到管道 */ 
		Execve(filename, emptylist, environ); 
	}
	//Wait(NULL);
	Read(httpsp[0],data,MAXLINE);
	SSL_write(ssl,data,strlen(data));
    }
    else
    #endif
    {
    	Dup2(fd,STDOUT_FILENO);        /* Redirct stdout to client */ 
	Execve(filename, emptylist, environ); 
    }
}

post方法外部程序(c语言)例子

#include "wrap.h"
#include "parse.h"

int main(void) {
    char *buf,*p;
    int length=0;
    char content[MAXLINE],data[MAXLINE];


    if ((buf = getenv("CONTENT-LENGTH")) != NULL)
    {
    	length=atol(buf);
    }
    
    p=fgets(data,length+1,stdin);
    if(p==NULL)
    	sprintf(content, "Something is wrong\r\n");
    else	
	sprintf(content, "Info:%s\r\n",data);

    printf("Content-length: %d\r\n", strlen(content));
    printf("Content-type: text/html\r\n\r\n");
    printf("%s", content);
    fflush(stdout);
    exit(0);

}
发布了53 篇原创文章 · 获赞 5 · 访问量 2335

猜你喜欢

转载自blog.csdn.net/qq_25490573/article/details/102988514