Transcript Socket

Web Server
王宏瑾
1
Induction (1)
Web
Server
HTTP/1.0
Browser
TCP/IP
Server
Client
2
Induction (2)
Create a socket
( port : 80 )
Bind
Listen
Accept
網
路
部
分
Web Server
接收 HTTP需求資料
包含需求標頭和需求主體
送出 HTTP回覆資料
包含回覆標頭和回覆主體
工
作
3
Socket (1)
• Socket ID
– Protocol
– IP Address
– Port number
• Association
– Protocol
– Local IP Address
– Local Port number
– Remote IP Address
– Remote Port number
Socket descriptor
通訊協定
本地IP位址
本地PORT
遠端IP位址
遠端PORT
4
Socket (2)
• Socket Type
– Stream socket
• byte-stream of two-way, reliable, sequenced, fullduplex and out-of-band
• connection-oriented ( TCP/IP )
– Datagram socket
• datagram-stream of two-way, unreliable
• connectionless ( UDP )
5
Socket (3)
socket()
bind()
(可有可無)
connect()
Winsock應用
程式介面
Socket descriptor
通訊協定
本地IP位址
本地PORT
遠端IP位址
遠端PORT
網路系統
TCP Client 程式
6
Socket (4)
socket()
Socket descriptor
通訊協定
bind()
本地IP位址
本地PORT
listen()
遠端IP位址
accept()
遠端PORT
Winsock應用
程式介面
網路系統
TCP Server 程式
7
Web Server
• 類別層級架構分為七部分
–
–
–
–
–
–
–
System Environment (使工作平台與程式內部分離)
Client Information (記錄工作環境與socket)
Service Provider (接收Client端的資料)
Service Response (處理各種的回應)
Service Request (擷取 HTTP需求資料)
Access of Resource (使用HKEY與HANDLE)
Exception (異常狀況之處理)
8
Web Server - Object Class (1)
System Environment
Service Provider
IBasicEnv
CBasicClient
Cwin32TCPEnv
CHttpAgent
Cwin32TCPEnv_2
Client Information
CClientStub
9
Web Server - Object Class (2)
Service Response
Service Request
IHttpResponse
CHttpRequest
CDocumeResponse
CDirectoryResponse
CCgiResponse
Access of Resource
Cwin32InScopeRegistryKey
Cwin32InScopeHandle
10
Web Server - Object Class (3)
Exception
ENSocket ( in IBasicEnv )
EPortNotOpen ( in IBasicEnv )
EbadSocket ( in IBasicEnv )
EsvncTimeout ( in IBasicEnv )
ETooManyService ( in IBasicEnv )
EInternalError ( in IhttpResponse )
ECgiErrorError ( in IhttpResponse )
EHttpConfig ( in Cwin32TCPEnv_2 )
EContentAccess ( in Cwin32TCPEnv_2 )
11
Program
int main( void )
{// Abstraction for the underlying system
CWin32TCPEnv_2 Env ;
做一些初始化的動作
char msg[ 256 ] ;
try{ 主程式部分 }
catch ( 哪種異常狀況 )
{ 對應處理方式 }
return 0;
}
異
常
處
理
catch( IBasicEnv::ENoSocket & )
{Env.ShowError( "ERR> TCP/IP stack error." ) ;}
catch( IBasicEnv::EBadSocket & )
{Env.ShowError( "ERR> Server socket is bad." ) ;}
catch( IBasicEnv::EPortNotOpen & )
{Env.ShowError( "ERR> Server port not open." ) ;}
catch( IBasicEnv::ETooManyServices & )
{Env.ShowError( "ERR> Too many services are running." ) ;}
12
Env.ReadyPort( 80 ) ;
for( int id = 1; TRUE; id++ )
{
sprintf( msg, "SERVER> Ready to serve browser #%d...", id ) ;
主
Env.ShowStatus( msg ) ;
程
// Block here until client arrives
式
Env.SpawnService( Env.BlockForClient( 80 ), ::HttpdThread, 80 ) ;
}
// Wait here when both service threads have started
Env.ShowStatus( "SERVER> Waiting for service threads to end..." ) ;
Env.ReadyPort( 80 );
create a socket
指定port為80
bind
listen
13
Web Server
Env.SpawnService( Env.BlockForClient( 80 ), ::HttpdThread, 80 ) ;
Env.BlockForClient( 80 )
等待Client端建立連線,並傳回socket
::HttpdThread
處理Client端送來的資料 ( 判斷是否合法讀取 )
送出HTTP回覆資料
Env.SpawnService
Create Thread去負責Client端送來的另外資料
14
HTTP Request
GET /home.html HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg,
application/msword*
Referer: http://140.112.29.172:80/
Accept-Language: zh-tw
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows NT)
Host: 140.112.29.172:80
Connection: Keep-Alive
15
Web Server
• Http需求資料
– 需求標頭 : 需求指令 ( 需求方法 資源名稱 適用的HTTP規格版本 )
與其他資訊
– 需求主體 : 其他資訊
• Http回覆資料
– 回覆標頭 : 狀態指令 ( 回覆資料的格式版本 所求資源的狀況 )
與其他資訊
– 回覆主體 : 其他資訊
• 詳細內容請參考 rfc1945
16
Web Server
DWORD __stdcall HttpdThread( LPVOID lpArg )
{
// Client will be automatically disconnected once out of this thread
CHttpAgent BernersLee( (CClientStub *)lpArg ) ;
BernersLee.Engage() ;
return 0 ;
}
CHttpAgent::CHttpAgent( CClientStub *pStub )
:CBasicClient( pStub )
{}
17
Web Server
Engage() :
CHttpRequest theRequest( this ) ;
CWin32TCPEnv_2 *pEnv = (CWin32TCPEnv_2 *)m_pEnv ;
try
{
IHttpResponse *pResponse ;
// Attempt to resolve client request
pResponse = theRequest.Resolve() ; (處理Client端送來的資料)
pResponse->Deliver() ;
(送出HTTP回覆資料)
}
catch (…)
{ 異常處理
}
18
pResponse = theRequest.Resolve() ;
IHttpResponse *CHttpRequest::Resolve( void )
{
// 每個request只由一個Request Object來服務
if( m_pResponse != NULL )
return m_pResponse ;
// 接受Client端的Request Header
m_pAgent->ReceiveUntilStr( m_szHeader, sizeof( m_szHeader ), 0,
CRLF CRLF, 4 ) ;
// Determine if the service is proxy or local
if( ::strlen( GetScheme() ) > 0 )
throw ENoRemoteSupport() ;
if( !GetEnv()->IsResourcePublic( GetUri() ) ) //讀取的Path是否合法
throw EInvalidRequest() ;
if( GetEnv()->IsResourceDirectory( GetUri() ) ) //是否為Directory
return new CDirectoryResponse( this ) ;
if( ::strlen( GetCgiExecutable() ) > 0 )
//是否為可執行檔
return new CCgiResponse( this ) ;
return new CDocumentResponse( this ) ;
}
19
Web Server
pResponse->Deliver() ;
若pResponse是指CDirectoryResponse( )
則顯示出目錄內容
若pResponse是指CCgiResponse( )
則執行 CGI 服務
若pResponse是指CDocumentResponse( )
則顯示出顯示出檔案內容
20
Web Server
• 將input存成一個檔案
• 以此作為欲執行的CGI程式之input
• 將CGI程式執行完後的結果輸出到檔案
• 最後再將此檔傳回Client端
21
Web Server
• 由於整個程式是採用Exception Handling的機制,所以
有可能exception發生後,使得一些在程式尾端的資源
釋放動作不被執行到,所以採用更安全的資源控制方
式。
• Cin32InScopeRegistryKey 與 Cwin32InScopeHandle 分
別對應到Win32環境下的 HKEY 及 HANDLE 兩種資源
種類,這兩種資源要被 ::RegCloseKey 和 ::CloseHandle
來釋放,當一個變數的生命期結束時,此變數的
Destructor會被呼叫,而達到釋放資源的效果。
22
Client
處 // HTTP Request header: GET uri ... CRLF CRLF
理 ReceiveUntilStr( szInBuffer, sizeof( szInBuffer ), 0, " ", 1 ) ;
ShowStatus( "HTTPAGENT> Request method:" ) ;
ShowStatus( szInBuffer ) ;
端 ReceiveUntilStr( szUri, sizeof( szUri ), 0, " ", 1 ) ;
送
來 ShowStatus( "HTTPAGENT> Request URI:" ) ;
的 ShowStatus( szUri ) ;
資 // Must receive all header until it ends in CRLF+CRLF
料 ReceiveUntilStr( szInBuffer, sizeof( szInBuffer ), 0, CRLF CRLF, 4 ) ;
// Attempt to resolve client request
HTTP
char szResponse[ 1024 ] ;
送 CWin32TCPEnv_2 *pEnv = (CWin32TCPEnv_2 *)m_pEnv ;
出 int cbResource = pEnv->GetResourceLength( szUri ) ;
回
覆
資
料
::wsprintf( szResponse,"HTTP/1.0 200 OK" CRLF
"CONTENT-LENGTH: %d" CRLF CRLF, cbResource ) ;
SendUntilDone( szResponse, strlen( szResponse ), 0 ) ;
pEnv->SendResource( m_Socket, szUri ) ;
23