精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>编程开发>>C/C++>>网络与通讯>>对ISAPI的深入应用

主题:对ISAPI的深入应用
发信人: tgm98()
整理人: girlrong(1999-11-13 15:17:12), 站内信件
这是我在写ISAPI时的心得,请各位指教

利用HTTP 协议(1.0 ver以上)进行连续不间断的通讯
一、总述:
在平常的应用中,CLIENT和SERVER间的通讯经常要求在一开始连通后,一直保持
连接,这样可使得SERVER方可以主动发信息给CLIENT端,而不需要CLIENT以轮询
的方式定时去与SERVER沟通,以取得SERVER发来的信息。这种方式用TCP/IP的SO
CKET编程是很容易实现的,因为SERVER端可以用一个单独的SOCKET来保持与CLIE
NT的连接,只要双方的SOCKET没有关闭,任何一方均可主动发送信息。但HTTP的
连接方式是一次性的,因此,要让SERVER端主动发送信息就比较困难,经过仔细
探索,发现可用以下两种方法来解决这个问题。
二、所采用方法的软件平台及协议的版本:
WEB SERVER :IIS 3.0 以上
HTTP :1.0 以上
BROWSER:IE 4.0以上
三、解决方法
方法一:
在telnet中,用get 方法,取得站点的输出,便可得到所有基于TCP/IP的回复信
息,这样可以观察到HTTP的头信息等,便于研究服务器发送回数据的全过程。
从以前的经验知道,从服务器的ISAPI程序中返回信息给CLIENT一般是采用*pCtx
t << _T(strRet),其中strRet为SERVER要发送的信息,但这种方法有一个特点,
即IIS先把strRet放在某一BUFFER中,必须等处理函数RETURN时,IIS才把BUFFER
中的strRet信息发送到CLIENT去,这样,无论你在函数中是分开发送的(亦即有
时间间隔的),但对CLIENT来说,总是一串连续的数据流一次接受完成。
那么,只要找出一个方法,能使得在SERVER的处理函数中及时把信息发送(即不
经过BUFFER的延迟),这样就可构造循环来保持与CLIENT的连接,并可在循环中
不断而及时地把信息发送回CLIENT,这个方法就是pECB->WriteClient( pECB->C
onnID,szContent, &dwSize,HSE_IO_SYNC),如果ISAPI是用MFC构造的,则可用p
Ctxt->m_pECB-> WriteClient( pCtxt->m_pECB->ConnID,szContent, &dwSize,H
SE_IO_SYNC)。下面实现连续的HTTP通讯:
1、在客户端建立两个线程,一个用于接受数据,一个用于发送数据,接受数据的
线程一旦连上,就不再断开,以循环的方式使线程一直存在,而发送线程则每次
都重新连接,亦即发送完本次数据后,线程结束。
2、在服务器端也建立两个线程,一个用于接受数据,一个用于发送数据,发送数
据的线程一旦连上,就不再断开,线程一直存在,而接受线程则每次都重新连接
,亦即接受完本次数据后,线程结束。接受来的数据当然要放在一个已建立的PU
BLIC BUFFER ARRAY中,以便各个线程都可以取用。
但这样的方法有一个缺点,即服务器端的开销较大,因为,对每个已连上的客户
,至少要有一个线程与其保持连接,这样,如果有100个客户同时上来,则必须至
少100个线程在与其连接,如果客户发送数据,则还要针对每个客户另开一个线

方法二:
如果能象TCP/IP得到SOCKET那样,得到一个指向连接的指针(或句柄,对象),
并且在SERVER的处理函数返回时,不断开与CLIENT的连接,该指针保持在全局BU
FFER里,使得SERVER要主动发信息给CLIENT时,可取得该指针所指向的连接通道
,进行通讯。这样,就可以和TCP/IP一样通讯了。
在HTTP 协议1.0 VERSION 以上,提供了KEEP-ALIVE的不中断连接方式,其本质是
一次HTTP连接后,SERVER 和CLIENT 间的TCP/IP连接仍然保持,下一次的HTTP请
求用的仍然是该TCP/IP通道。
经过测试,既得到了一个指向连接的指针,并且该指针能保留到全局BUFFER里,
下面是测试程序:
//KEEP.DLL
#define WIN32_LEAN_AND_MEAN 
#include <windows.h> 
#include <httpext.h> 
#include <stdio.h> 
 
EXTENSION_CONTROL_BLOCK* pECBRe=NULL;
int iCount=0;

BOOL WINAPI  
GetExtensionVersion( OUT HSE_VERSION_INFO * pVer ) 

    pVer->dwExtensionVersion=MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_M
AJOR); 
    strncpy( pVer->lpszExtensionDesc, "ISAPI Keep-Alive Sample",      
   HSE_MAX_EXT_DLL_NAME_LEN ); 
    return TRUE; 

DWORD WINAPI HttpExtensionProc(IN EXTENSION_CONTROL_BLOCK * pECB ) 

    char szHeader[] =  
        "Connection: Keep-Alive\r\n" 
        "Content-Length: %lu\r\n" 
        "Content-type: text/html\r\n\r\n"; 
 
    char szContent[] =  
        "<html> <form method=get action=\\Keep.dll>" 
        "<h1>First Sample</h1><hr>" 
        "<input type=submit value=\"Send Request\"></form></html>"
    char szBuffer[4096]; 
    HSE_SEND_HEADER_EX_INFO HeaderExInfo; 
    DWORD dwSize; 
     
    sprintf( szBuffer, szHeader, strlen( szContent ) ); 
    HeaderExInfo.pszHeader = szBuffer; 
    HeaderExInfo.cchHeader = strlen( szBuffer ); 
    HeaderExInfo.pszStatus = "200 OK"; 
    HeaderExInfo.cchStatus = strlen( HeaderExInfo.pszStatus ); 
    HeaderExInfo.fKeepConn = TRUE; 
// char buffer[1024];
// DWORD dwbufferSize=sizeof(buffer);
// char ip[]="REMOTE_ADDR";
// pECB->GetServerVariable(pECB- >ConnID,(LPTSTR)ip,(LPVOID)buffer,&dw
bufferSize);
iCount++;
if(iCount>1)
{
    char szContent1[] =  
    "<html> <form method=get action=\\Keep.dll>" 
"<h1>Second Sample</h1><hr>" 
"<input type=submit value=\"Send Request\"></form></html>"
    dwSize = strlen( szContent1 ); 
  pECBRe->WriteClient(pECBRe->ConnID,szContent1,&dwSize, HSE_IO_SYNC 
); 
}
pECB->ServerSupportFunction(  
        pECB->ConnID, 
        HSE_REQ_SEND_RESPONSE_HEADER_EX, 
        &HeaderExInfo, 
        NULL, 
        NULL 
        ); 
    dwSize = strlen( szContent ); 
    pECB->WriteClient( pECB->ConnID, szContent, &dwSize, HSE_IO_SYNC )

if(iCount==1)
{
pECBRe=pECB;
}
    return HSE_STATUS_SUCCESS_AND_KEEP_CONN; 


BOOL WINAPI 
TerminateExtension( IN DWORD dwFlags ) 

    return TRUE; 


注解: 1、定义两个全程变量:iCount,  pECBRe
2、在返回的HEAD中包含"Connection: Keep-Alive\r\n" 
3、在处理函数返回时应返回
HSE_STATUS_SUCCESS_AND_KEEP_CONN
4、在这次测试中,有甲乙两台客户机参与。
A、甲发请求KEEP.DLL
B、KEEP.DLL返回包含有"Connection: Keep-Alive\r\n"的HEAD,
CONTENT,RETURN时返回
HSE_STATUS_SUCCESS_AND_KEEP_CONN
同时,把甲与服务器的用于连接的pECB保存在全程变量pECBRe
这样,甲与服务器的这一次请求完成后,仍保持着TCP/IP的连
接。
C、乙发请求KEEP.DLL
D、因为iCount的记数已大于1,所以,KEEP.DLL会把信息发送到
pECBRe所指向的连接,即服务器与甲的连接,并向甲发送信
息,这时,可从甲的浏览器上看到服务器发来的信息。
E、同时,KEEP.DLL也会发送信息回乙方。
F、当甲方按停止按钮后,KEEP.DLL中的pECBRe所指向的BUFFER
由IIS自动收回,以便分配给下一个连接使用。
G、要服务器方主动切断与甲的连接,目前测试了许多方法,均不
奏效。
H、如要转到基于MFC的DLL程序中,亦是一样的。
I、 如果客户端用WININET  API写的程序,其连接原理也应是一致
的。
J、 按MICROSOFT的文档说明,如果客户方使用了PROXY 
SERVER,且是MICROSOFT的PROXY  SERVER,Keep-Alive
是允许的,即可通过PROXY  SERVER。

--
不要对我说生命中辉煌的事,
不要对我说失败是命运的事,
那些在经验里我只相信一次,
因为我和你一样,
要这样走过一生,
我只有低头前进。 

※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.96.190.64]

[关闭][返回]