6

HTTPストリームに接続し、消費したテキストデータをログに記録するクライアントがあります。

ストリーミングサーバーにHTTPGETリクエストを送信します...サーバーは応答してデータを継続的に公開します...テキストを公開するか、定期的にping(テキスト)メッセージを送信します...接続を閉じることはありません。

消費するデータをノンブロッキングで読み取ってログに記録する必要があります。

私はこのようなことをしています:

import urllib2

req = urllib2.urlopen(url)    
for dat in req: 
    with open('out.txt', 'a') as f:        
        f.write(dat) 

私の質問は次のとおり
です。ストリームが継続している場合、これはブロックされますか?
各チャンクで読み取られるデータの量と、それを指定/調整できますか?
これはhttpストリームを読み取り/ログに記録するための最良の方法ですか?

4

4 に答える 4

6

ねえ、それは 3 つの質問を 1 つにまとめたものです。;-)

サーバーが非常に高速にデータを生成している場合でも、ネットワークのボトルネックにより、理論上は読み取りがブロックされる可能性があります。

「for dat in req」を使用して URL データを読み取ることは、一度に 1 行ずつ読み取ることを意味します。画像などのバイナリ データを読み取る場合はあまり役に立ちません。を使用すると、より適切に制御できます。

chunk = req.read(size)

もちろんブロックできます。

それが最善の方法であるかどうかは、質問で利用できない詳細に依存します。たとえば、ブロッキング呼び出しなしで実行する必要がある場合は、Twistedのようなフレームワークを検討する必要があります。ブロッキングに足を引っ張られたくないし、Twisted を使いたくない場合 (これは、物事を行うブロッキング方法に比べてまったく新しいパラダイムです)、スレッドをスピンアップして読み取りと書き込みを行うことができます。あなたのメインスレッドが楽しい道を進んでいる間:

def func(req):
    #code the read from URL stream and write to file here

...

t = threading.Thread(target=func)
t.start() # will execute func in a separate thread
...
t.join() # will wait for spawned thread to die

もちろん、エラー チェックや例外処理などは省略していますが、全体像を把握するにはこれで十分だと思います。

于 2009-10-12T22:19:36.913 に答える
3

高レベルのインターフェイスを使用しているため、ブロック サイズのブロックやバッファリングなどの問題を適切に制御できません。非同期インターフェイスにまで行きたくない場合 (その場合は、すでに提案されているtwistedに勝るものはありません!)、標準ライブラリに含まれているhttplibを試してみませんか? HTTPResponse インスタンスメソッドは、返されたオブジェクトの同様のメソッドよりも、バイト.read(amount)を読み取るために必要な期間を超えてブロックする可能性が高くなります(確かに、どちらのモジュールについても文書化された仕様はありませんが...)。amounturlopen

于 2009-10-13T03:34:29.790 に答える
2

別のオプションは、socketモジュールを直接使用することです。接続を確立し、HTTP 要求を送信し、ソケットを非ブロッキング モードに設定してから、socket.recv()「リソースが一時的に利用できません」という例外を処理してデータを読み取ります (つまり、読み取るものがないことを意味します)。非常に大まかな例は次のとおりです。

import socket, time

BUFSIZE = 1024

s = socket.socket()
s.connect(('localhost', 1234))
s.send('GET /path HTTP/1.0\n\n')
s.setblocking(False)

running = True

while running:
    try:
        print "Attempting to read from socket..."
        while True:
            data = s.recv(BUFSIZE)
            if len(data) == 0:      # remote end closed
                print "Remote end closed"
                running = False
                break
            print "Received %d bytes: %r" % (len(data), data)
    except socket.error, e:
        if e[0] != 11:      # Resource temporarily unavailable
            print e
            raise

    # perform other program tasks
    print "Sleeping..."
    time.sleep(1)

ただし、urllib.urlopen()Web サーバーがリダイレクトする場合はいくつかの利点があり、URL ベースの基本認証などが必要ですselect。読み取るデータがあるときに通知するモジュールを利用できます。

于 2009-10-14T06:13:33.390 に答える
1

はい、サーバーに追いつくと、サーバーがさらにデータを生成するまでブロックされます

各データは、最後に改行を含む 1 行になります

ツイストは良いオプションです

あなたの例では with と for を交換しますが、到着するすべての行に対してファイルを開いたり閉じたりしたいですか?

于 2009-10-12T22:52:05.600 に答える