標籤:
0x00 起
最近在做一個對時間要求比較高的掃描器,需要封裝一下SOCKET類比HTTP發包的一些常用函數。簡單的說,就是重寫一下requests中的get、post方法。
今天在寫的時候,遇到一枚很奇怪的問題,對同一個URL,POST請求能正常返回資訊,而一旦切到GET,socket time out。
虛擬碼如下:
get_str = ‘GET %s HTTP/1.1\r\nHost: %s\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36\r\nAccept: */*\r\n\r\n‘post_str = ‘POST %s HTTP/1.1\r\nHost: %s\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36\r\n\r\n%s\r\n\r\n‘def get(url,port): sock = socket.connect(url,port) sock.send(get_str % (url, port)) response = ‘‘ temp = sock.recv(4096) while temp: temp = sock.recv(4096) response += temp return response
0x10 結
心煩意亂的調了很久無果,出去吃了個飯,回來查查資料,從頭開始順了一遍,找到了bug點。原因是HTTP 1.1協議中,預設connection: keep-alive。
Connection: keep-alive 當一個網頁開啟完成後,用戶端和伺服器之間用於傳輸HTTP資料的TCP串連不會關閉,如果用戶端再次訪問這個伺服器上的網頁,會繼續使用這一條已經建立的串連
Connection: close 代表一個Request完成後,用戶端和伺服器之間用於傳輸HTTP資料的TCP串連會關閉, 當用戶端再次發送Request,需要重建立立TCP串連。
而python中的sock.recv如果接收不到資料,會等到TCP串連down掉,才會返回NULL。如果在程式中沒有設定逾時時間,會等到伺服器主動中斷連線,一般是30s~60s。
這就是造成socket timeout的原因。在http request裡添加connection: close即可解決問題。但是為什麼只有get受到影響,post卻沒有問題呢?
做了個簡單的測試:
post 很快就返回了結果:
而get用了很久才返回結果,其中connection為keep-alive:
所以,之前所說的HTTP 1.1協議中,所有的請求都預設為Connection: keep-alive是錯誤的認識。
只有get請求會預設採取Connection: keep-alive
參考資料:
https://www.byvoid.com/blog/http-keep-alive-header
Python socket類比HTTP請求