파이썬에서 연결이 끊어 졌는지 확인하는 방법
내 파이썬 응용 프로그램이 다른 쪽 소켓이 떨어졌을 때 알 수 있기를 바랍니다. 이것에 대한 방법이 있습니까?
"dropped"가 의미하는 바에 따라 다릅니다. TCP 소켓의 경우, 다른 쪽 끝이 close () 또는 프로세스 종료를 통해 연결을 닫으면 파일 끝을 읽거나 읽기 오류가 발생하는 것을 알 수 있습니다. 일반적으로 errno는 'connection reset by 피어 '는 운영 체제에 따라 다릅니다. 파이썬의 경우 길이가 0 인 문자열을 읽거나 소켓에서 읽거나 쓰려고 할 때 socket.error가 발생합니다.
짧은 대답:
비 블로킹 recv () 또는 매우 짧은 시간 제한이있는 차단 recv () / select ()를 사용하십시오.
긴 대답 :
소켓 연결을 처리하는 방법은 필요에 따라 읽거나 쓰고 연결 오류를 처리 할 준비를하는 것입니다.
TCP는 연결을 "삭제"하는 3 가지 형태 (시간 초과, 재설정, 닫기)를 구분합니다.
이 중 시간 초과는 실제로 감지 할 수 없으며 TCP는 시간이 아직 만료되지 않았 음을 알려줄 수 있습니다. 그러나 그것이 당신에게 말했더라도 시간은 여전히 곧 만료 될 수 있습니다.
또한 사용자 또는 피어 (연결의 다른 쪽 끝)가 shutdown ()을 사용하면 들어오는 바이트 스트림 만 닫고 나가는 바이트 스트림을 계속 실행하거나 나가는 스트림을 닫고 들어오는 스트림을 계속 실행할 수 있습니다.
엄밀히 말하면 읽기 스트림이 닫혀 있는지, 쓰기 스트림이 닫혀 있는지 또는 둘 다 닫혀 있는지 확인하고 싶습니다.
연결이 "삭제"된 경우에도 여전히 네트워크 버퍼에있는 데이터를 읽을 수 있어야합니다. 버퍼가 비워진 후에 만 recv ()에서 연결이 끊어집니다.
연결이 끊어 졌는지 확인하는 것은 "현재 버퍼링 된 모든 데이터를 읽은 후 무엇을 받게됩니까?"라고 묻는 것과 같습니다. 이를 확인하려면 현재 버퍼링 된 모든 데이터를 읽어야합니다.
"버퍼링 된 모든 데이터를 읽는 것"이 어떤 사람들에게는 여전히 문제가 될 수 있다는 것을 알 수 있습니다. 여전히 recv ()를 블로킹 함수로 생각합니다. recv ()를 차단하면 버퍼가 이미 비어있을 때 읽기를 "검사"하면 차단되어 "검사"의 목적을 무효화합니다.
내 생각에 전체 프로세스를 무기한으로 차단하도록 문서화 된 모든 기능은 설계상의 결함이지만, 일반 파일 설명자처럼 소켓을 사용하는 것이 멋진 아이디어 였기 때문에 역사적인 이유로 여전히 존재한다고 생각합니다.
할 수있는 일은 다음과 같습니다.
- 소켓을 비 차단 모드로 설정하지만 수신 버퍼가 비어 있거나 송신 버퍼가 꽉 찼음을 나타내는 시스템 종속 오류가 발생합니다.
- 차단 모드를 고수하지만 소켓 시간 제한을 매우 짧게 설정하십시오. 이렇게하면 recv ()로 소켓을 "ping"또는 "확인"할 수 있습니다.
- 매우 짧은 시간 제한으로 select () 호출 또는 asyncore 모듈을 사용하십시오. 오류보고는 여전히 시스템에 따라 다릅니다.
문제의 쓰기 부분의 경우 읽기 버퍼를 비워두면 거의 문제가 해결됩니다. non-blocking 읽기 시도 후에 "dropped"된 연결을 발견 할 것이며, 읽기가 닫힌 채널을 반환 한 후에는 어떤 것도 전송을 중지하도록 선택할 수 있습니다.
전송 된 데이터가 다른 쪽 끝에 도달했는지 확인하는 유일한 방법은 다음 중 하나입니다 (아직 전송 버퍼에 있지 않음).
- 보낸 정확한 메시지에 대해 동일한 소켓에서 적절한 응답을받습니다. 기본적으로 더 높은 수준의 프로토콜을 사용하여 확인을 제공합니다.
- 소켓에서 성공적인 shutdow () 및 close () 수행
파이썬 소켓 하우투는 send ()가 채널이 닫히면 쓰여진 0 바이트를 반환한다고 말합니다. non-blocking 또는 timeout socket.send ()를 사용할 수 있으며 0을 반환하면 해당 소켓에서 더 이상 데이터를 보낼 수 없습니다. 그러나 0이 아닌 값을 반환하면 이미 무언가를 보낸 것입니다. 행운을 빕니다 :)
또한 여기에서는 OOB (대역 외) 소켓 데이터를 문제에 접근하는 수단으로 고려하지 않았지만 OOB가 의미하는 바가 아니라고 생각합니다.
Jweede가 게시 한 링크에서 :
예외 socket.timeout :
This exception is raised when a timeout occurs on a socket which has had timeouts enabled via a prior call to settimeout(). The accompanying value is a string whose value is currently always “timed out”.
다음은 Python 문서 의 소켓 모듈에 대한 데모 서버 및 클라이언트 프로그램입니다.
# Echo server program
import socket
HOST = '' # Symbolic name meaning all available interfaces
PORT = 50007 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print 'Connected by', addr
while 1:
data = conn.recv(1024)
if not data: break
conn.send(data)
conn.close()
그리고 클라이언트 :
# Echo client program
import socket
HOST = 'daring.cwi.nl' # The remote host
PORT = 50007 # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
s.send('Hello, world')
data = s.recv(1024)
s.close()
print 'Received', repr(data)
내가 가져온 문서 예제 페이지에는이 아이디어를 사용하는 더 복잡한 예제가 있지만 여기에 간단한 대답이 있습니다.
클라이언트 프로그램을 작성한다고 가정하면 소켓이 떨어질 위험이있을 때 소켓을 사용하는 모든 코드를 try 블록 안에 넣으십시오.
try:
s.connect((HOST, PORT))
s.send("Hello, World!")
...
except socket.timeout:
# whatever you need to do when the connection is dropped
이 블로그 게시물의 코드 샘플을 Python : 클라이언트가 연결을 닫을 때 감지하는 방법? , 그리고 그것은 나를 위해 잘 작동합니다.
from ctypes import (
CDLL, c_int, POINTER, Structure, c_void_p, c_size_t,
c_short, c_ssize_t, c_char, ARRAY
)
__all__ = 'is_remote_alive',
class pollfd(Structure):
_fields_ = (
('fd', c_int),
('events', c_short),
('revents', c_short),
)
MSG_DONTWAIT = 0x40
MSG_PEEK = 0x02
EPOLLIN = 0x001
EPOLLPRI = 0x002
EPOLLRDNORM = 0x040
libc = CDLL(None)
recv = libc.recv
recv.restype = c_ssize_t
recv.argtypes = c_int, c_void_p, c_size_t, c_int
poll = libc.poll
poll.restype = c_int
poll.argtypes = POINTER(pollfd), c_int, c_int
class IsRemoteAlive: # not needed, only for debugging
def __init__(self, alive, msg):
self.alive = alive
self.msg = msg
def __str__(self):
return self.msg
def __repr__(self):
return 'IsRemoteClosed(%r,%r)' % (self.alive, self.msg)
def __bool__(self):
return self.alive
def is_remote_alive(fd):
fileno = getattr(fd, 'fileno', None)
if fileno is not None:
if hasattr(fileno, '__call__'):
fd = fileno()
else:
fd = fileno
p = pollfd(fd=fd, events=EPOLLIN|EPOLLPRI|EPOLLRDNORM, revents=0)
result = poll(p, 1, 0)
if not result:
return IsRemoteAlive(True, 'empty')
buf = ARRAY(c_char, 1)()
result = recv(fd, buf, len(buf), MSG_DONTWAIT|MSG_PEEK)
if result > 0:
return IsRemoteAlive(True, 'readable')
elif result == 0:
return IsRemoteAlive(False, 'closed')
else:
return IsRemoteAlive(False, 'errored')
내가 착각하지 않는다면 이것은 일반적으로 시간 제한을 통해 처리됩니다 .
참조 URL : https://stackoverflow.com/questions/667640/how-to-tell-if-a-connection-is-dead-in-python
'program story' 카테고리의 다른 글
파이썬 데코레이터는 함수가 클래스에 속한다는 것을 잊게 만듭니다. (0) | 2020.12.24 |
---|---|
루트 컨텍스트를 어떻게 지정합니까? (0) | 2020.12.24 |
C #에서 두 배열 간의 "차이"를 얻습니까? (0) | 2020.12.15 |
이 C # 프로그램에서 인쇄 할 열 이름을 어떻게 얻습니까? (0) | 2020.12.15 |
슬라이스 표기법을 사용하여 목록 반전 (0) | 2020.12.15 |