linux cgi httprequest 请求

// HttpRequest.h
#if !defined(_HTTP_REQUEST_H_INCLUDED_)
#define _HTTP_REQUEST_H_INCLUDED_
#include <string>
#define HTTP_BUFFER_SIZE            256    
#define HTTP_STATUS_INFORMATION     100
#define HTTP_STATUS_OK              200
#define HTTP_STATUS_REDIRECTION     300
#define HTTP_STATUS_REQUEST_ERROR   400
#define HTTP_STATUS_SERVER_ERROR    500
#define HTTP_STATUS_UNKNOWN         600
#define HTTP_STATUS_REDIRECT        302
#define SERVER_NAME_SIZE 127
#define URL_PARAM_SIZE  255
#define URL_PART_SIZE  127
using namespace std;
struct URLEntry
{
	char szServerName[SERVER_NAME_SIZE + 1];
	int nPort;
	char szUrl[URL_PART_SIZE + 1];
	char szParams[URL_PARAM_SIZE + 1];
};
char *raw2url(char *dst, const char *src);
char* UriEncode(const char* lpszSrc, char* lpszBuf, int nBufLen); 
char* UriDecode(char *lpszSrc);
class CHttpRequest 
{
protected:
	static const char* m_szEmptyString;
	char    m_Error[1024];  //存放错误信息
	int     m_BuffLen;      //HTTP缓冲区的长度
	int     m_Socket;       //当前的SOCKET
	int     m_Connect;      //当前的连接
	char*   m_Buffer;       //存放HTTP响应的缓冲区
	char*   m_Head;         //请求结果的HEAD
	char*   m_Body;         //请求结果的页面内容
	char*   m_Host;         //HTTP服务器地址
	unsigned short m_Port;  //HTTP服务器端口号
public:
	CHttpRequest(const char* lpszServer, unsigned short nPort = 80);
	virtual ~CHttpRequest();

	bool    OpenRequest(const char* lpszMethod, const char* lpszURI,
		const char* lpszData = NULL, const char* lpszHeader = NULL);

	const char* GetError() { return m_Error; }
	const char* GetHead() { return m_Head; }
	const char* GetBody() { return m_Body; }
	int     GetStatus();
	static int parseURL(char *szURL, URLEntry *urlEntry); //把URL拆分成服务器名称、端口号和参数三部分
	static string getURL(URLEntry &entry); //根据指定的URL实体合成URL
protected:
	char* CreateRequestHeader( const char* lpszMethod, const char* lpszURI, const char* lpszData = NULL, const char* lpszHeader = NULL );
	bool IncreaseBuffer( size_t incsize );
	bool ReAllocBuffer(size_t buffsize);
	bool SplitContent();
	bool ReceiveContent();
	bool SendRequest(const char* lpszMethod, const char* lpszURI,
		const char* lpszData, const char* lpszHeader);
	bool    Connect();
	bool    IsConnected() { return (m_Connect == 0); }
};
#endif
<pre name="code" class="cpp">// HttpRequest.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "HttpRequest.h"
#define closesocket close
typedef struct sockaddr_in SOCKADDR_IN;
const char ERR_SOCKET[]             =   "无法建立到服务器的连接:服务器连接错误。";
const char ERR_CONNECT[]            =   "无法连接到服务器:服务器忙或没有响应。";
const char ERR_UNKNOWNHOST[]        =   "找不到服务器:未知的服务器地址。";
const char ERR_SENDURL[]            =   "无法发送HTTP请求:服务器忙或没有响应。";
const char ERR_SENDHEADER[]         =   "无法发送HTTP请求:服务器忙或没有响应。";
const char ERR_SENDDATA[]           =   "无法发送HTTP请求数据:服务器忙或没有响应。";
const char ERR_NOCONTENT[]          =   "服务器没有返回信息。";
const char ERR_CANNOTRECEIVE[]      =   "无法从服务器接受信息:服务器忙或没有响应。";
const char ERR_MEMORY[]             =   "服务器错误:服务器程序无法完成操作。";
const char HTTP_ERR_INFORMATION[]   =   "服务器返回信息。";
const char HTTP_ERR_OK[]            =   "操作成功完成。";
const char HTTP_ERR_REDIRECTION[]   =   "请求被重服务器重定向。";
const char HTTP_ERR_REQUEST[]       =   "无效的HTTP请求(可能是错误的连接)。";
const char HTTP_ERR_SERVER[]        =   "服务器发生内部错误。";
const char HTTP_ERR_UNKNOWN[]       =   "服务器发生未知错误。";

static const char* c_szHttpErrDesc[] = {
	HTTP_ERR_UNKNOWN,
	HTTP_ERR_INFORMATION,
	HTTP_ERR_OK,   
	HTTP_ERR_REDIRECTION,
	HTTP_ERR_REQUEST,
	HTTP_ERR_SERVER
};

static signed char _res_esc_ch [] = {
	2, 2, 2, 2, 2, 2, 2, 2,  2, 2, 2, 2, 2, 2, 2, 2,
	2, 2, 2, 2, 2, 2, 2, 2,  2, 2, 2, 2, 2, 2, 2, 2,
	2,-1, 2, 2, 1, 2, 1,-1, -1,-1,-1, 1, 1,-1,-1, 1,
	0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 1, 1, 2, 1, 2, 1,
	1, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 2, 2, 2, 2,-1,
	2, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 2, 2, 2,-1, 2
};
char *raw2url(char *dst, const char *src)
{
	register const unsigned char *s;
	register char *d;
	register int c, sc;
	for (s = (const unsigned char *)src, d = dst; (c = *s++); )
	{
		if ((c < 128 && _res_esc_ch[c] != 0))
		{
			*d++ = '%';
			sc = (0xf0 & c) >> 4;
			*d++ = (sc < 10) ? sc + '0' : sc - 10 + 'A';
			sc = 0x0f & c;
			*d++ = (sc < 10) ? sc + '0' : sc - 10 + 'A';
		}
		else
		{
			*d++ = c;
		}
	}
	*d = '\0';
	return dst;
}

char* UriEncode(const char* lpszSrc, char* lpszBuf, int nBufLen)
{
	const char szReservedChar[] = {';' , '/' , '?' , ':' , '@' , '&' , '=' , '+'};
	const char szUnsafeChar[] = { ' ' , '"' , '#' , '%' , '<' , '>' };
	int nSrcLen= strlen(lpszSrc);
	int nEncLen = nSrcLen * 3 + 0x10;
	char *lpszEnc = new char[nEncLen];
	if(!lpszEnc) return NULL;
	nEncLen = 0;
	while(*lpszSrc)
	{
		if( iscntrl(*lpszSrc) || strchr(szReservedChar, *lpszSrc) ||
			strchr(szUnsafeChar, *lpszSrc) )
		{
			nEncLen += sprintf(lpszEnc + nEncLen, "%%%02X", *(lpszSrc++));
		}
		else
		{
			lpszEnc[nEncLen++] = *(lpszSrc++);
		}
		lpszEnc[nEncLen] = '\0';
	}
	lpszEnc[nEncLen] = '\0';
	if(nBufLen < nEncLen+1)
	{
		delete[] lpszEnc;
		return NULL;
	}
	strcpy(lpszBuf,lpszEnc);
	delete[] lpszEnc;
	return lpszBuf;
}

char* UriDecode(char *lpszSrc)
{
	char* lpszEnc = lpszSrc;
	char* lpszDec = lpszSrc;
	int   nDecChar;
	while( *lpszEnc ) {
		if( *lpszEnc == '+' ) {
			*lpszDec ++ = ' ';
			lpszEnc++;
		}
		else if( *lpszEnc == '%' &&
			isxdigit(lpszEnc[1]) && isxdigit(lpszEnc[2]) ) {
				sscanf(lpszEnc+1, "%2x", &nDecChar);
				lpszEnc += 3;
				*lpszDec ++ = (char)nDecChar;
		}
		else
			*lpszDec ++ = *lpszEnc ++;
	}
	*lpszDec = 0;
	return lpszSrc;
}

const char* CHttpRequest::m_szEmptyString = "";
static const char* c_szHttpVersion = "HTTP/1.0";
static const char* c_szHttpRequestHeader ="Accept: *)";

CHttpRequest::CHttpRequest(const char* lpszServer, unsigned short nPort/* = 80*/)
{
	m_Host      = new char[strlen(lpszServer)+1];
	strcpy(m_Host, lpszServer);
	m_Port      = nPort;
	m_Buffer    = NULL;
	m_Head      = NULL;
	m_Body      = NULL;
	m_BuffLen   = 0;
	m_Error[0]  = '\0';
	m_Socket    = -1;
	m_Connect   = -1;
}

CHttpRequest::~CHttpRequest()
{
	if ( m_Host ) delete m_Host;
	if ( m_Buffer ) delete m_Buffer;
	if ( m_Socket ) closesocket(m_Socket);
	return;
}
bool CHttpRequest::Connect()
{
	if( IsConnected() ) // Already connected.
		return true;
	if( !ReAllocBuffer( HTTP_BUFFER_SIZE ) )
		return false;
	m_Socket = socket(AF_INET,SOCK_STREAM ,0);
	if(m_Socket < 0) {
		strcpy(m_Error, ERR_SOCKET);
		return false;
	}
	SOCKADDR_IN sin;
	sin.sin_family  = AF_INET;
	sin.sin_port    = htons((u_short)m_Port);       // HTTP Port
	long addr   = inet_addr(m_Host);                // HTTP Server
	if (addr == INADDR_NONE)
	{
		struct hostent * lptmpHostent;
		lptmpHostent = gethostbyname(m_Host);
		if (lptmpHostent == NULL) {
			strcpy(m_Error, ERR_UNKNOWNHOST);
			addr=0;
		}
		else
			addr = *(unsigned long*)lptmpHostent->h_addr_list[0];
	}
	sin.sin_addr.s_addr = addr;
	m_Connect   = connect(m_Socket,(struct sockaddr*)&sin,sizeof(sin));
	if( m_Connect != 0 )
	{
		strcpy(m_Error, ERR_CONNECT);
		if ( m_Socket ) closesocket(m_Socket);
		return false;
	}
	*m_Error    = 0;
	return true;
}

bool CHttpRequest::OpenRequest(const char* lpszMethod, const char* lpszURI,
							   const char* lpszData, const char* lpszHeader)
{
	if( !Connect() ) return false;
	if( !SendRequest(lpszMethod, lpszURI, lpszData, lpszHeader) ) return false;
	if( !ReceiveContent() ) return false;
	if( !SplitContent() ) return false;
	int nStatus = GetStatus();
	if( nStatus != HTTP_STATUS_OK )
		return false;
	else
		return true;
}
bool CHttpRequest::SendRequest(const char* lpszMethod, const char* lpszURI,
							   const char* lpszData, const char* lpszHeader)
{
	if( !lpszMethod || !lpszURI ) return false;

	char* lpszReqHdr = CreateRequestHeader(lpszMethod, lpszURI, lpszData, lpszHeader);
	if( !lpszReqHdr ) return false;
	int nReqHdrLen = strlen(lpszReqHdr);

#ifdef  LINUX_DEBUG
	PDEBUG("%s,(%d)\n",lpszReqHdr,nReqHdrLen);
#endif
	int nSent = send(m_Socket,lpszReqHdr,nReqHdrLen,0);
	delete[] lpszReqHdr;
	if( nSent != nReqHdrLen )
	{
		strcpy(m_Error, ERR_SENDHEADER);
		return false;
	}
#ifdef  LINUX_DEBUG
	PDEBUG("Send Request Header OK!\n");
#endif

	if( strcmp(lpszMethod, "POST")==0 && lpszData) {
		nSent = send(m_Socket,lpszData,strlen(lpszData),0);
		if( nSent != nSent ) {
			strcpy(m_Error, ERR_SENDDATA);
			return false;
		}
	}
#ifdef  LINUX_DEBUG
	PDEBUG("Send Request OK!\n");
#endif
	return true;
}
bool CHttpRequest::ReceiveContent()
{
	char recvbuf[HTTP_BUFFER_SIZE+1];
	long len = 0;
	if( !ReAllocBuffer( 1 ) )
		return false;
	do {
		len = recv(m_Socket, recvbuf, HTTP_BUFFER_SIZE,0);
		if(len<0)
		{
			strcpy(m_Error, ERR_CANNOTRECEIVE);
			return false;
		}
		if( len == 0 )  break;
		recvbuf[len] = '\0';
#ifdef  LINUX_DEBUG
		PDEBUG("Received OK!\n%s\n", recvbuf);
#endif
		if( !IncreaseBuffer( len ) )
			return false;
		strcat(m_Buffer, recvbuf);
	}while( len > 0 );
	return true;
}
bool CHttpRequest::SplitContent()
{
	if( !m_Buffer ) return false;
	m_Head = strstr(m_Buffer, "\r\n");
	if( !m_Head ) {
		m_Body  = m_Buffer+ strlen(m_Buffer);
		strcpy(m_Error, ERR_NOCONTENT);
		return false;
	}
	m_Head[0] = 0;
	m_Head += 2;
	strcpy(m_Error, m_Buffer);
	m_Body = strstr(m_Head, "\r\n\r\n");
	if ( !m_Body ) {
		m_Body  = m_Head+ strlen(m_Head);
		strcpy(m_Error, ERR_NOCONTENT);
		return false;
	}
	m_Body[2]   = '\0';
	m_Body      += 4;
	return true;
}
bool CHttpRequest::ReAllocBuffer(size_t buffsize)
{
	if( buffsize < 0 )
		return false;
	if( m_Buffer )
	{
		delete m_Buffer;
		m_Buffer = NULL;
		m_BuffLen = 0;
	}
	if( buffsize == 0 )
		return true;
	if( !(m_Buffer = new char[buffsize]) )
	{
		strcpy(m_Error, ERR_MEMORY);
		return false;
	}
	memset(m_Buffer, 0, buffsize);
	m_Head  = m_Buffer;
	m_Body  = m_Buffer;
	m_BuffLen   = buffsize;
	return true;
}
bool CHttpRequest::IncreaseBuffer(size_t incsize)
{
	char* lpszEnc = m_Buffer;
	if( !(m_Buffer = new char[m_BuffLen + incsize]) )
	{
		strcpy(m_Error, ERR_MEMORY);
		return false;
	}
	m_BuffLen += incsize;
	memset(m_Buffer, 0, m_BuffLen);
	if( lpszEnc )
	{
		strcpy(m_Buffer, lpszEnc);
		delete lpszEnc;
	}
	m_Head  = m_Buffer;
	m_Body  = m_Buffer;
	return true;
}
int CHttpRequest::GetStatus()
{
	const char szHttpHead[] = "HTTP/1.x ";
	const int  nHttpHeadLen = strlen(szHttpHead);
	int nHttpStatus = 0;
	if( !m_Error[0] ) return 0;
	if( strstr(m_Error, "HTTP/1.") != m_Error ||
		sscanf(m_Error+nHttpHeadLen, "%d", &nHttpStatus) != 1 )
		return 0;

	if( nHttpStatus>=HTTP_STATUS_OK && nHttpStatus<HTTP_STATUS_REDIRECTION )
		nHttpStatus = HTTP_STATUS_OK;
	else if( nHttpStatus<HTTP_STATUS_INFORMATION || nHttpStatus>HTTP_STATUS_UNKNOWN)
		nHttpStatus = HTTP_STATUS_UNKNOWN;
	return nHttpStatus;
}
char* CHttpRequest::CreateRequestHeader(const char *lpszMethod, const char *lpszURI,
										const char *lpszData, const char *lpszHeader)
{
	if( !lpszMethod || !lpszURI ) return false;
	char* lpszReqHdr = NULL;
	bool bPost = false;
	int nPostDataLen = lpszData ? strlen(lpszData) : 0;
	int nReqHdrLen = 0;

	nReqHdrLen = strlen(lpszMethod) + strlen(lpszURI) + 256;
	if( lpszHeader ) nReqHdrLen += strlen(lpszHeader);
	if( strcmp(lpszMethod, "POST") == 0 )
		bPost = true;
	else if ( lpszData )
		nReqHdrLen += nPostDataLen;
	if( !(lpszReqHdr = new char[nReqHdrLen]) )
		return NULL;

	if( !bPost ) {
		if( lpszData )
			sprintf(lpszReqHdr, "%s %s?%s HTTP/1.0\r\n"
			"Connection: close\r\n", lpszMethod, lpszURI, lpszData);
		else
			sprintf(lpszReqHdr, "%s %s HTTP/1.0\r\n"
			"Connection: close\r\n", lpszMethod, lpszURI);
	}
	else {
		sprintf(lpszReqHdr, "%s %s HTTP/1.0\r\n"
			"Connection: close\r\n", lpszMethod, lpszURI);
		nReqHdrLen = strlen(lpszReqHdr);
		sprintf(lpszReqHdr+nReqHdrLen, "Content-Type: application/x-www-form-urlencoded\r\nContent-Length: %d\r\n", nPostDataLen);
	}
	if( lpszHeader ) {
		strcat(lpszReqHdr, lpszHeader);
		strcat(lpszReqHdr, "\r\n");
	}

	strcat(lpszReqHdr, "\r\n");
	return lpszReqHdr;
}

int CHttpRequest::parseURL(char *szURL, URLEntry *urlEntry)
{
	char *szServerName = urlEntry->szServerName;
	const int nServerNameSize = SERVER_NAME_SIZE;
	int *nPort = &(urlEntry->nPort);
	char *urlParams = urlEntry->szParams;
	const int nParamSize = URL_PARAM_SIZE;
	char *szUrl = urlEntry->szUrl;
	const int nUrlSize = URL_PARAM_SIZE;
	const char * _HTTP_TAG = "http://";
	int urlLen = strlen(szURL);
	int _HTTP_TAG_LEN = strlen(_HTTP_TAG);
	*nPort = 80;
	if (urlLen <= _HTTP_TAG_LEN)
	{
		szServerName[0] = '\0';
		urlParams[0] = '\0';
		szUrl[0] = '\0';
		return -1;
	}
	char *pBegin;
	char *pMoved;
	int nServerNameLen;
	char *szPort;
	pMoved = pBegin = szURL + _HTTP_TAG_LEN;
	while(*pMoved && *pMoved != '/' && *pMoved != ':')
	{
		pMoved++;
	}
	nServerNameLen = pMoved - pBegin;
	if (nServerNameLen > nServerNameSize)
	{
		nServerNameLen = nServerNameSize;
	}
	strncpy(szServerName, pBegin, nServerNameLen);
	szServerName[nServerNameLen] = '\0';
	if (*pMoved  == ':')
	{
		pMoved++;
		szPort = pMoved;
		while (*pMoved && *pMoved != '/')
		{
			pMoved++;
		}
		*nPort = atoi(szPort);
	}
	char *pUrlBegin = pMoved;
	while (*pMoved && *pMoved != '?')
	{
		pMoved++;
	}

	urlLen = pMoved - pUrlBegin;
	if (urlLen > 0)
	{
		if (urlLen > nUrlSize)
		{
			urlLen = nUrlSize;
		}
		strncpy(szUrl, pUrlBegin, urlLen);
		szUrl[urlLen] = '\0';
	}
	else
	{
		szUrl[0] = '\0';
	}
	if (*pMoved == '?')
	{
		pMoved += 1;  
	}
	int paramLen = strlen(pMoved);
	if (paramLen > nParamSize)
	{
		paramLen = nParamSize;
	}

	if (paramLen > 0)
	{
		strncpy(urlParams, pMoved, paramLen);
	}
	urlParams[paramLen] = '\0';
	return 0;
}

std::string CHttpRequest::getURL(URLEntry &entry)
{
    char szPort[16];
    std::string szURL("http://");
    sprintf(szPort, ":%d", entry.nPort);
    szURL += entry.szServerName;
    szURL += szPort;
    szURL += entry.szUrl;
    szURL += string("?");
    szURL += entry.szParams;
    return szURL;
}

调用例子:
 
CHttpRequest httpRequest("172.16.13.25", 5280);  
    bool ret = httpRequest.OpenRequest("GET","http://172.16.13.25:5280/mystat");  
    int nStatus = httpRequest.GetStatus();  
    const char *content = httpRequest.GetBody();  
    int contentLen = strlen(content); 

代码来源 :http://blog.sina.com.cn/s/blog_4f10165f0100bsdp.html


为什么要进行CGI编程?  
在HTML中,当客户填写了表单,并按下了发送(submit)按钮后,表单的内容被发送到了服务器端,一般的,这时就需要有一个服务器端脚本来对表单的内容进行一些处理,或者是把它们保存起来,或者是按内容进行一些查询,或者是一些别的什么。没有了CGI,WEB的世界就完全失去了它的交互性,所有的信息都变成单向的了,而不能够有任何的反馈。  
有的人认为可以用JavaScript来代替CGI程序,这其实是一个概念上的错误。JavaScript只能够在客户浏览器中运行,而CGI却是工作在服务器上的。他们所做的工作有一些交集,比如表单数据验证一类的,但是JavaScript是绝对无法取代CGI的。但可以这样说,如果一项工作即能够用 JavaScript来做,又可以用CGI来做,那么绝对要使用JavaScript,在执行的速度上,JavaScript比CGI有着先天的优势。只有那些在客户端解决不了的问题,比如和某个远程数据库交互,这时就应该使用CGI了。  
简单的说来,CGI是用来沟通HTML表单和服务器端程序的接口(interface)。说它是接口,也就是说CGI并不是一种语言,而是可以被其他语言所应用的一个规范集。理论上讲,你可以用任何的程序语言来编写CGI程序,只要在编程的时候符合CGI规范所定义的一些东西就可以了。由于C语言在平台无关性上表现不错(几乎在任何的系统平台下都有其相应编译器),而且对大多数程序员而言都算得上很熟悉(不像Perl),因此,C是CGI编程的首选语言之一。这儿我们介绍的,就是如何使用C来编写CGI程序。  
  作为CGI编程的最为简单的例子,就是进行表单的处理。因而在这篇文章中,我们主要介绍的就是如何用C来编写CGI程序来进行表但处理。  
  GET表单的处理  
对于那些使用了属性“METHOD=GET”的表单(或者没有METHOD属性,这时候GET是其缺省值),CGI定义为:当表单被发送到服务器端后,表单中的数据被保存在服务器上一个叫做QUERY_STRING的环境变量中。这种表单的处理相对简单,只要读取环境变量就可以了。这一点对不同的语言有不同的做法。在C语言中,你可以用库函数getenv(定义在标准库函数stdlib中)来把环境变量的值作为一个字符串来存取。你可以在取得了字符串中的数据后,运用一些小技巧进行类型的转换,这都是比较简单的了。在CGI程序中的标准输出(output)(比如在C中的stdout文件流)也是经过重定义了的。它并没有在服务器上产生任何的输出内容,而是被重定向到客户浏览器。这样,如果编写一个C的CGI程序的时候,把一个HTML文档输出到它的 stdout上,这个HTML文档会被在客户端的浏览器中显示出来。这也是CGI程序的一个基本原理。  
  我们来看看具体的程序实现,下面是一段HTML表单:  
< FORM ACTION="/cgi-bin/mult.cgi" >  
< P >请在下面填入乘数和被乘数,按下确定后可以看到结果。  
< INPUT NAME="m" SIZE="5" >  
< INPUT NAME="n" SIZE="5" >< BR >  
< INPUT TYPE="SUBMIT" VALUE="确定" >  
< /FORM >  
  我们要实现的功能很简单,就是把表单中输入的数值乘起来,然后输出结果。其实这个功能完全可以用JavaScript来实现,但为了让程序尽量的简单易懂,我还是选择了这个小小的乘法来作为示例。  
  下面就是处理这个表单的CGI程序,对应于FORM标签中的ACTION属性值。  
#include < stdio.h >  
#include < stdlib.h >  
int main(void)  
{  
char *data;  
long m,n;  
printf("%s%c%c ","Content-Type:text/html;charset=gb2312",13,10);  
printf("< TITLE >乘法结果< /TITLE > ");  
printf("< H3 >乘法结果< /H3 > ");  
data = getenv("QUERY_STRING");  
if(data == NULL)  
printf("< P >错误!数据没有被输入或者数据传输有问题");  
else if(sscanf(data,"m=%ld&n=%ld",&m,&n)!=2)  
printf("< P >错误!输入数据非法。表单中输入的必须是数字。");  
else  
printf("< P >%ld和%ld的成绩是:%ld。",m,n,m*n);  
return 0;  
}  
  具体的C语法就不多讲了,我们来看看它作为CGI程序所特殊的地方。  
  前面已经提到标准输出的内容就是要被显示在浏览器中的内容。第一行的输出内容是必须的,也是一个CGI程序所特有的:printf("%s%c%c ","Content-Type:text/html",13,10),这个输出是作为HTML的文件头。因为CGI不仅可以像浏览器输出HTML文本,而且可以输出图像,声音之类的东西。这一行告诉浏览器如何处理接受到的内容。在Content-Type的定义后面跟有两行的空行,这也是不可缺少的。因为所有CGI程序的头部输出都是相近的,因而可以为其定义一个函数,来节省编程的时间。这是CGI编程常用的一个技巧。  
  程序在后面调用了用了库函数getevn来得到QUERY_STRING的内容,然后使用sscanf函数把每个参数值取出来,要注意的是sscanf函数的用法。其他的就没有什么了,和一般的C程序没有区别。  
  把程序编译后,改名为mult.cgi放在/cgi-bin/目录下面,就可以被表单调用了。这样,一个处理GET方式表单的CGI程序就大功告成了。  
  POST表单处理  
下面我们来考虑另外一种表单传送方法:POST。假设我们要实现的任务是这样的:把表单中客户输入的一段文本内容添加到服务器上的一个文本文件的后面。这可以看作是一个留言版程序的雏形。显然,这个工作是无法用JavaScript这种客户端脚本来实现,也算得上真正意义上的CGI程序了。  
看起来这个问题和上面讲的内容很相近,仅仅是用不同的表单和不同的脚本(程序)而已。但实际上,这中间是有一些区别的。在上面的例子中,GET的处理方法可以看作是“纯查询(pure query)”类型的,也就是说,它与状态无关。同样的数据可以被提交任意的次数,而不会引起任何的问题(除了服务器的一些小小的开销)。但是现在的任务就不同了,至少它要改变一个文件的内容。因而,可以说它是与状态有关的。这也算是POST和GET的区别之一。而且,GET对于表单的长度是有限制的,而 POST则不然,这也是在这个任务中选用POST方法的主要原因。但相对的,对GET的处理速度就要比POST快一些。  
在CGI的定义中,对于POST类型的表单,其内容被送到CGI程序的标准输入(在C语言中是stdin),而被传送的长度被放在环境变量 CONTENT_LENGTH中。因而我们要做的就是,在标准输入中读入CONTENT_LENGTH长度的字符串。从标准输出读入数据听起来似乎要比从环境变量中读数据来的要容易一些,其实则不然,有一些细节地方要注意,这在下面的程序中可以看到。特别要注意的一点就是:CGI程序和一般的程序有所不同,一般的程序在读完了一个文件流的内容之后,会得到一个EOF的标志。但在CGI程序的表单处理过程中,EOF是永远不会出现的,所以千万不要读多于 CONTENT_LENGTH长度的字符,否这会有什么后果,谁也不知道(CGI规范中没有定义,一般根据服务器不同而有不同得处理方法)。  
  我们来看看到底如何从POST表单收集数据到CGI程序,下面給出了一個比较简单的C源代碼:  
#include < stdio.h >  
#include < stdlib.h >  
#define MAXLEN 80  
#define EXTRA 5  
/* 4个字节留给字段的名字"data", 1个字节留给"=" */  
#define MAXINPUT MAXLEN+EXTRA+2  
/* 1个字节留给换行符,还有一个留给后面的NULL */  
#define DATAFILE "../data/data.txt"  
/* 要被添加数据的文件 */  
void unencode(char *src, char *last, char *dest)  
{  
for(; src != last; src++, dest++)  
if(*src == "+")  
*dest = " ";  
else if(*src == "%") {  
int code;  
if(sscanf(src+1, "%2x", &code) != 1) code = "?";  
*dest = code;  
src +=2; }  
else  
*dest = *src;  
*dest = " ";  
*++dest = "";  
}  
int main(void)  
{  
char *lenstr;  
char input[MAXINPUT], data[MAXINPUT];  
long len;  
printf("%s%c%c ",  
"Content-Type:text/html;charset=gb2312",13,10);  
printf("< TITLE >Response< /TITLE > ");  
lenstr = getenv("CONTENT_LENGTH");  
if(lenstr == NULL || sscanf(lenstr,"%ld",&len)!=1 || len > MAXLEN)  
printf("< P >表单提交错误");  
else {  
FILE *f;  
fgets(input, len+1, stdin);  
unencode(input+EXTRA, input+len, data);  
f = fopen(DATAFILE, "a");  
if(f == NULL)  
printf("< P >对不起,意外错误,不能够保存你的数据 ");  
else  
fputs(data, f);  
fclose(f);  
printf("< P >非常感谢,您的数据已经被保存< BR >%s",data);  
}  
return 0;  
}  
  从本质上来看,程序先从CONTENT_LENGTH环境变量中得到数据的字长,然后读取相应长度的字符串。因为数据内容在传输的过程中是经过了编码的,所以必须进行相应的解码。编码的规则很简单,主要的有这几条:  
  1. 表单中每个每个字段用字段名后跟等号,再接上上这个字段的值来表示,每个字段之间的内容用&连结;  
  2. 所有的空格符号用加号代替,所以在编码码段中出现空格是非法的;  
  3. 特殊的字符比如标点符号,和一些有特定意义的字符如“+”,用百分号后跟其对应的ACSII码值来表示。  
  例如:如果用户输入的是:  
  Hello there!  
  那么数据传送到服务器的时候经过编码,就变成了data=Hello+there%21 上面的unencode()函数就是用来把编码后的数据进行解码的。在解码完成后,数据被添加到data.txt文件的尾部,并在浏览其中回显出来。  
  把文件编译完成后,把它改名为collect.cgi后放在CGI目录中就可以被表单调用了。下面给出了其相应的表单:  
< FORM ACTION="/cgi-bin/collect.cgi" METHOD="POST" >  
< P >请输入您的留言(最多80个字符):< BR >< INPUT NAME="data" SIZE="60" MAXLENGTH="80" >< BR >  
< INPUT TYPE="SUBMIT" VALUE="确定" >  
< /FORM >  
事实上,这个程序只能作为例子,是不能够正式的使用的。它漏掉了很关键的一个问题:当有多个用户同时像文件写入数据是,肯定会有错误发生。而对于一个这样的程序而言,文件被同时写入的几率是很大的。因此,在比较正式的留言版程序中,都需要做一些更多的考虑,比如加入一个信号量,或者是借助于一个钥匙文件等。因为那只是编程的技巧问题,在这儿就不多说了。  
  最后,我们来写一个浏览data.txt文件的的CGI程序,这只需要把内容输出到stdout就可以了:  
  #include < stdio.h >  
  #include < stdlib.h >  
  #define DATAFILE "../data/data.txt"  
  int main(void)  
  {  
  FILE *f = fopen(DATAFILE,"r");  
  int ch;  
  if(f == NULL) {  
  printf("%s%c%c ",  
  "Content-Type:text/html;charset=gb2312",13,10);  
  printf("< TITLE >错误 < /TITLE > ");  
  printf("< P >< EM >意外错误,无法打开文件< /EM >"); }  
  else {  
  printf("%s%c%c ",  
  "Content-Type:text/plain",13,10);  
  while((ch=getc(f)) != EOF)  
  putchar(ch);  
  fclose(f); }  
  return 0;  
  }  
  这个程序唯一要注意的是:它并没有把data.txt 包装成HTML格式后再输出,而是直接作为简单文本(plain text)输出,这只要在输出的头部用text/plain类型代替text/html就可以了,浏览器会根据Content-Type的类型自动的选择相应的处理方法。  
  要触发这个程序也很简单,因为没有数据要输入,所以只需一个按钮就可以搞定了:  
  < FORM ACTION="/cgi-bin/viewdata.cgi" >  
  < P >< INPUT TYPE="SUBMIT" VALUE="察看" >  
  < /FORM >  
  到这儿,一些基本的用C编写CGI程序的原理就将完了。当然,就凭讲的这些内容,还很难编写出一个好的CGI程序,这需要进一步的学习CGI的规范定义,以及一些其他的CGI编程特有的技巧。  

这篇文章的目的,也就是要你了解一下CGI编程的概念。事实上,现在的一些主流的服务器端脚本编程语言如ASP,PHP,JSP等,都基本上具备了CGI 编程的大部分的功能,但他们在使用上的,确实是比无论用什么语言进行CGI编程都要容易的多。所以在进行服务器端编程的时候,一般都会首先考虑使用这些脚本编程语言。只有当他们也解决不了,比如要进行一些更为底层的编程的时候,才会用到CGI。


解释说明:htmlhttp://www.cnblogs.com/hnrainll/archive/2011/06/02/2067667.html

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在进行HTTP请求时,若请求的目标接口使用了HTTPS协议,则需要进行HTTPS连接。HTTPS连接的安全性要比HTTP连接高,因为它使用了SSL/TLS协议对请求和响应进行加密。在进行HTTPS连接时,需要完成以下步骤: 1. 首先,需要将HTTPS地址解析为IP地址和端口号。 2. 在完成地址解析后,需要使用Socket准备好与HTTPS服务器建立连接的通道。 3. 建立连接后,发送一份HTTP请求头给HTTPS服务器,请求头中需要包含请求的方式、路径、协议版本和发送的数据。 4. 发送请求头后,HTTPS服务器会发送回一份HTTP响应头,响应头中需要包含响应的状态码、协议版本和响应数据的长度等信息。 5. 根据HTTP响应头中的状态码来判断请求是否成功,如果成功,则可以继续读取响应体中的数据。 6. 在读取响应体中的数据时,需要注意数据是否已经全部到达,否则会产生数据被截断的情况。 7. 在读取完响应体后,需要关闭与HTTPS服务器的连接。 总之,在进行HTTP请求时,对于使用HTTPS协议的接口,需要对请求进行额外的处理保证安全连接性。 ### 回答2: 首先,了解HTTP请求是什么。HTTP请求是指客户端向服务端发送请求,然后服务端返回响应。HTTP请求通常包含请求方法、URL、请求头部、请求体等组成部分。 接下来,需要了解HTTPS接口。HTTPS是一种加密的HTTP请求,安全性更高。HTTPS使用SSL协议实现数据加密,保证了数据的安全性和完整性。 当我们使用HTTP请求HTTPS接口时,我们需要遵循以下步骤: 1.建立SSL连接:客户端需要向服务端发送握手请求,进行SSL协议的版本协商、加密算法协商等,然后将握手信息进行加密发送给服务端。 2.服务端响应握手:服务端收到请求后进行响应,返回SSL协议版本、加密算法等信息。 3.证书验证:客户端会对服务端返回的证书进行验证,以确保它是由受信任的CA颁发的有效证书。 4.建立安全通道:一旦证书验证通过,客户端和服务端就会建立安全通道,开始进行加密通信。 5.发送HTTP请求:在安全通道建立完毕后,客户端就可以发送HTTP请求了。请求内容也是经过加密的。 6.服务端响应:服务端接收到加密的HTTP请求后,进行解密操作,然后返回加密的HTTP响应,客户端也进行解密操作后得到明文响应。 总之,HTTP请求HTTPS接口需要经过SSL握手和证书验证等多个步骤,确保通信的安全性。我们需要使用相应的工具,如HttpClient等来实现。同时,我们还需要对服务器端的证书进行验证,以减少安全风险。 ### 回答3: HttpRequest是用于网页发送HTTP请求的类,而HTTPS是指在HTTP协议下加入SSL层,使传输过程中的数据被加密保护,提高了数据的安全性。 当我们需要通过网络通信获取数据时,常用HttpRequest请求接口实现数据返回。当需要访问HTTPS接口时,可以使用以下方法: 1. 在HttpRequest请求对象中设置访问的URL:使用HTTPS开头的URL地址 HttpRequest request = new HttpRequest("https://www.example.com/api/get_data"); 2. 设置HTTPS的信任证书:由于HTTPS为加密协议,过程中涉及证书的验证。一般情况下是从对方网站获得的证书,也可以通过第三方认证机构获得。在程序层面,需要为访问HTTPS服务设置信任证书 Security.setProperty("ssl.SocketFactory.provider", "com.sun.net.ssl.internal.ssl.Provider"); System.setProperty("javax.net.ssl.trustStoreType", "jks"); System.setProperty("javax.net.ssl.trustStore", "truststore.jks"); 3. 执行HttpRequest请求并解析返回数据 HttpResponse response = request.getResponse(); String content = response.getContent(); 这样,当我们发送包含HTTPS协议的接口请求时,便可以得到返回结果了。需要注意的是,在请求HTTPS接口的过程中,网络通信的数据是被加密的,因此访问效率可能会有所降低。这时,我们需要权衡数据安全性和访问效率,选择适合自己的方案。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值