2009-03-23 23 views
3

私はTLSを使用する必要のあるPythonでHTTPクライアントを持っています。暗号化された接続を行うだけでなく、 リモートマシン(証明書の発行者など)から情報を取得するために、 だけでなく、私は多くのHTTPサーバーへの接続を にする必要があります。しばしば悪い動作をするので、私は絶対に にタイムアウトが必要です。 TLS以外の接続の場合、 mysocket.settimeout(5)は私がしたいことをします。多くのTLS Pythonモジュールの中でTLS接続(タイムアウトあり)

gnutls.errors.OperationWouldBlock: Function was interrupted. 

python-opensslは、同様の問題があります:

python-gnutlsが、それは、非ブロッキングソケットを使用 ためのソケット上のsetTimeout()を使用することはできません。

OpenSSL.SSL.WantReadError 

標準ライブラリのSSL moduleは、Pythonでは機能しません2.5。

TLSliteのような他のライブラリは、明らかに証明書のメタデータを にアクセスできません。

プログラムはスレッド化されているため、信号は使用できません。私は詳細な HTTPダイアログボックスのコントロールが必要なので、urllib2のような標準ライブラリは使用できません。

背景:これは 調査プロジェクトDNSwitnessです。関連するスレッド:Timeout on a Python function callおよびHow to limit execution time of a function call in Python

答えて

1

私はこの目的のために決して使ったことはありませんが、Twistedはあなたが望むことを行うべきです。唯一の欠点は、それがかなり大きなライブラリであることです。また、PyOpenSSL(Twistedはそれに依存します)をインストールする必要があります。 Twistedのコールバックベースのアーキテクチャーはこれまで使用したことがない人にとっては慣れ親しんでいるかもしれません(開始する前にがほしいです)。

それ以外にも、たくさんの接続を管理するという考え方に基づいて設計されています。もちろん、タイムアウト、再接続などを指定したり、証明書情報を取得することもできます(here参照)。

1

私はPyOpenSSLを使用して接続を開いていて、常にWantReadError例外が発生するという問題があると想定しています。このエラーとタイムアウトを区別することはできません。次の例を考えてみましょう:

#!/usr/bin/python 

import OpenSSL 
import socket 
import struct 

context = OpenSSL.SSL.Context(OpenSSL.SSL.TLSv1_METHOD) 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.settimeout(5) 
connection = OpenSSL.SSL.Connection(context,s) 
connection.connect(("www.gmail.com",443)) 

# Put the socket in blocking mode 
connection.setblocking(1) 

# Set the timeout using the setsockopt 
tv = struct.pack('ii', int(6), int(0)) 
connection.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, tv) 

print "Connected to " , connection.getpeername() 
print "Sate " , connection.state_string() 

while True: 
    try: 
     connection.do_handshake() 
     break 
    except OpenSSL.SSL.WantReadError: 
     print "Exception" 
     pass 
print "Sate " , connection.state_string() 


print connection.send("koekoek\r\n") 


while True: 
    try: 
     recvstr = connection.recv(1024) 
     break 
    except OpenSSL.SSL.WantReadError: 
     print "Exception" 
     pass 

print recvstr 

これは、gmailへのSSL接続を開き、無効な文字列を送信し、応答を読み取り、印刷します。注: *接続はブロックモードに明示的に設定されています * recvタイムアウトは明示的にこの場合6秒に設定されています。

ここで、タイムアウトが発生すると、WantReadError例外が発生します(この場合、6秒間待機した後)。 (再試行を避けるためにTrueを削除することはできますが、この場合はテストのために追加しました)。ソケットで設定されたタイムアウトはconnect()呼び出しでのみ有効です。

GNUTLSの場合にもおそらく適用される非ブロッキングモードでソケットを保持する場合は、自分で計時を行い、呼び出しを開始した時刻を取得し、 :WantReadErrorを除いて、毎回自分でチェックを行って、あなたが長時間待たずにいるかどうかを確認します。

+0

しかし、それはプロセッサのための非常に高価ビジーウェイトのいくつかの並べ替え、ではないのですか? – bortzmeyer

+0

あなたはいつもスリープを挿入したり、スケジューラを稼働させたり、何か他のことをすることができます。ループの中で長い時間を費やしているかのように、いいサーバはかなり速く応答しようとします。 –

0

単純な解決策の1つは、操作によってソケットの種類を変更することです。私はGNUTLSでこれをテストし、それが働いた:

  1. のDoのsetTimeout()をソケットの上に、その方法は、connect()をGNUTLSで包まれた裸のソケットでconnect()を実行する前に、あなたが望んでいたとして、タイムアウトの対象となります。
  2. )あなたは(GNUTLSの握手前のsetTimeout(なし)またはsetblocking(1)でタイムアウトを削除していることを確認してください