2014-10-11 6 views
1

server_socket.accept()으로 생성 된 TCP 연결 소켓이 항상 닫혀 있는지 확인하기 위해 python with - with 문 (a.k.a. 컨텍스트 관리자)을 사용하려고합니다. 그러나 accept()이 여러 값을 반환하기 때문에 명백한 형식이 작동하지 않습니다.파이썬`with .. as .. '문과 다중 반환 값

반환 값이 여러 개인 함수에 with 문을 사용하는 방법이 있습니까?

최소 예제는 try/finally 블록을 바꾸기 위해 주석 처리 된 코드와 같은 것을 사용하고 싶습니다.

#!/usr/bin/env python3 

import socket 
from socket import socket as Socket 

with Socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket: 

     server_socket.bind(('', 8011)) 
     server_socket.listen(1) 
     print("server ready") 

     while True: 

      # with server_socket.accept() as (connection_socket, _): 
      #  request = connection_socket.recv(1024).decode('ascii') 
      #  reply = request.upper() 
      #  connection_socket.send(reply.encode('ascii')) 

      try: 
       connection_socket, _ = server_socket.accept() 
       request = connection_socket.recv(1024).decode('ascii') 
       reply = request.upper() 
       connection_socket.send(reply.encode('ascii')) 

      finally: 
       connection_socket.close() 

사용하여 오류 메시지와 함께 문입니다 주석 : 튜플이 with에 필요한 __exit__ 속성이 없기 때문에

Traceback (most recent call last): 
    File "./test.py", line 26, in <module> 
    with server_socket.accept() as (connection_socket, _): 
AttributeError: __exit__ 

는 아마도 이것이다.

답변

6

socket.socket의 반환 값에는 __exit____enter__을 구현하는 기본 제공 컨텍스트 관리자가 있습니다. accept에 의해 반환되는 튜플은하지 않지만, 추가 할 수있는 라이브러리가있다 :

import socket 
import contextlib 

@contextlib.contextmanager 
def accept(s): 
    c,a = s.accept() 
    print('client connected on',a) 
    yield c,a 
    print('client disconnected on',a) 
    c.close() 

with socket.socket() as s: 
    s.bind(('',8000)) 
    s.listen(1) 
    with accept(s) as (c,a): 
     while True: 
      data = c.recv(1024) 
      if not data: break 
      c.sendall(data) 

참조 :

https://docs.python.org/3.3/library/contextlib.html

추신 : Without contextlib :

import socket 

with socket.socket() as s: 
    s.bind(('',8000)) 
    s.listen(1) 
    with s.accept()[0] as c: 
     a = c.getpeername() 
     print('client connected on',a) 
     while True: 
      data = c.recv(1024) 
      if not data: break 
      c.sendall(data) 
     print('client disconnected on',a) 
+0

소켓 클래스에는 구현할 수 없습니까? 왜 그렇지 않은가? – dshepherd

+1

이것은'socket class'에서 구현됩니다. 그래서 첫 번째와 함께 작동합니다. 's'는'__exit__'과'__enter__' 메소드의 구현을 직접 포함합니다. s.accept() [0] as c :'와 같이's.accept()'와 함께'with '를 사용할 수 있지만 클라이언트 주소는 잃어 버릴 수 있습니다. 클라이언트 소켓 만이 컨텍스트 관리자 함수를 가지고 있지만,'accept'에 의해 반환 된 튜플은 그렇지 않습니다. –

+0

'contextlib '없이 작동하게했습니다. 편집을 참조하십시오. –