基於SSL(TLS)的HTTPS網頁下載——如何編寫健壯的可靠的網頁下載

源碼下載地址
案例開發環境:VS2010
本案例未使用openssl庫,內部提供了sslite.dll庫進行TLS會話,該庫提供了ISSLSession接口用於建立SSL會話。

HTTP協議很簡單,寫個簡單的socket程序通過GET命令就能把網頁給down下來。但接收大的網絡資源就複雜多了。何時解析、如何解析完整的HTTP響應頭,就是個頭疼問題。因為你不能指望一次recv就能接收完所有響應數據,也不能指望服務器先發送HTTP響應頭,然後再發送響應數據。只有把HTTP響應頭徹底解析了,我們才能知道後續接收的Body數據有多大,何時才能接收完畢。

比如通過響應頭的”Content-Length”字段,才能知道後續Body的大小。這個大小可能超過了你之前開闢的接收數據緩存區大小。當然你可以在得知Body大小後,重新開闢一個與”Content-Length”一樣大小的緩存區。但這樣做顯然是不明智的,比如你get的是一部4K高清藍光小電影,藍光電影不一定能get到,藍屏電腦倒有可能get到。。。。。。

遇到服務器明確給出”Content-Length”字段,是一件值得額手稱慶的大喜事,但不是每個IT民工都這麼幸運。如果遇到的是不靠譜的服務器,發送的是”Transfer-Encoding: chunked”,那你就必須鍛煉自己真正的解析和組織能力了。這些分塊傳輸的數據,顯然不會以你接收的節奏到達你的緩衝區,比如先接收到一個block塊大小,然後是一個完整的塊數據,很有可能你會接收到多個塊或者不完整的塊,這就需要你站在宏觀的角度把他們拼接起來。

如果你遇到的是甩的一米的服務器,它不僅給你的是chunked,而且還增加了”Content-Encoding: gzip”,那麼你就需要拼接後進行解壓,當然你也可能遇到的是”deflate”壓縮。
附:我寫過web服務器,所以也知道服務器的心理。。。。。。
HttpServer:一款Windows平台下基於IOCP模型的高並發輕量級web服務器

題外話:我一直困惑的是HTTP協議為何不是對分塊數據單獨gzip壓縮然後傳輸,而只能是整體gzip壓縮後再分塊傳輸。這個對大資源傳輸很關鍵,比如上面的4K高清藍光小電影,顯然不能通過gzip+chunked方式傳輸,土豪服務器例外。

當然你也可以用開源的llhttp來解析收到的http數據,從而避免上述可能會遇到的各種坑。最新版本的nodejs中就使用llhttp代替之前的的http-parser,據說解析效率有大幅提升。為此我下載了nodejs源碼,並編譯了一把,這是一個快樂的過程,因為你可以看到v8引擎,openssl,zlib等各種開源庫。。。。,不過llhttp只負責解析,不負責緩存,因此你還是需要在解析的過程中,進行數據緩存。
關於V8引擎的使用參見文章
V8引擎靜態庫及其調用方法

以下是sslite庫提供的接口,SSLConnect是建立連接,SSLHandShake是SSL握手,握手成功後即可調用SSLSend和SSLRecv進行數據接收和發送,非常簡單。如果接收數據很多,SSLRecv會通過回調函數將數據拋給調用層。

以下是源碼,注釋很多,就不一一解釋了。