2009-10-12 5 views
6

나는 HTTP 스트림에 연결하고 그것이 소비하는 텍스트 데이터를 기록하는 클라이언트를 가지고있다.HTTP 스트림에서 넌 블로킹 읽기/로그

스트리밍 서버에 HTTP GET 요청을 보냅니다 ... 서버가 응답하고 지속적으로 데이터를 게시합니다 ... 텍스트를 게시하거나 정기적으로 핑 (텍스트) 메시지를 보내고 절대로 연결을 닫지 않습니다.

소비하는 데이터를 비 차단 방식으로 읽고 로깅해야합니다.

나는 이런 일을하고있는 중이 야 :

import urllib2 

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

내 질문은 다음과 같습니다 스트림이 연속 될 때
이 이제까지 차단?
각 청크에서 얼마나 많은 데이터가 읽히고 지정/조정할 수 있습니까?
은 http 스트림을 읽고 로그하는 가장 좋은 방법입니까?

답변

3

블록 크기를 차단하고 버퍼링하는 것과 같은 문제에 대해 적절한 제어 기능을 사용하려면 너무 높은 수준의 인터페이스를 사용하고 있습니다. 비동기 인터페이스 (여기에 twisted, 이미 제안했듯이 이길 수 없다!)로 들어가기를 꺼려한다면 httplib은 표준 라이브러리에있는 것이 어떨까요? HTTPResponse 인스턴스 .read(amount) 메서드는 urlopen에 의해 반환 된 객체의 비슷한 메서드보다 amount 바이트를 읽는 데 더 이상 필요하지 않게 차단할 가능성이 큽니다 (물론 어느 모듈에도 해당 사양에 대한 설명이 없지만 ...).

6

안녕하세요, 세 질문입니다. ;-)

때때로 서버가 데이터를 빠르게 생성하더라도 네트워크 병목 현상으로 인해 읽기가 차단 될 수 있습니다.

"for dat in req"를 사용하여 URL 데이터를 읽는 것은 한 번에 한 줄씩 읽는 것을 의미합니다. 이미지와 같은 이진 데이터를 읽는 경우에는별로 유용하지 않습니다. 당신이 사용하는 경우 더 나은 컨트롤을 얻을

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 

분명히, 내가 생략 한 오류 검사/예외 처리 등을하지만, 희망 그것은 당신에게 사진을 제공하기 위해 충분히입니다 : 파일, 메인 스레드는 메리 길을가는 동안. 서버가 더 많은 데이터

각 날엔 트위스트 말

에 줄 바꿈을 포함하여 한 줄 것

을 생산 때까지 차단 서버 잡기

1

예는 좋은 옵션

입니다 귀하의 예를 들어 주위를 둘러 보았습니다. 실제로 도착한 모든 행에 대해 파일을 열고 닫으려고하십니까?

+0

for/with 주문은 고의적이었습니다. 이것은 각 쓰기로 파일 핸들을 열거 나 닫을 것입니다. 바쁜 스트림에 대해서는 효율적이지 않지만, 제 경우에는 스트림이 대부분 차단/대기하고 가끔씩 데이터를 수신합니다. –

3

또 다른 옵션은 socket 모듈을 직접 사용하는 것입니다. 연결을 설정하고 HTTP 요청을 보내고 소켓을 비 블로킹 모드로 설정 한 다음 socket.recv() '리소스 일시적으로 사용할 수 없음'예외 (처리 할 내용이 없음)를 처리하여 데이터를 읽습니다. 당신은 데이터가있을 때 당신은 당신을 말할 것이다 select 모듈의 사용을 만들 수있는 등 URL 기반의 기본 인증이 필요한 웹 서버 리디렉션 경우 urllib.urlopen() 몇 가지 장점이 있습니다, 그러나

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) 

: 매우 거친 예는 이것이다 읽다.