문제

파이썬으로 간단한 멀티 스레드 게임 서버를 작성하여 각 클라이언트 연결에 대한 새 스레드를 만듭니다. 나는 때때로 파이프/시그 파이프 오류로 인해 서버가 충돌한다는 것을 알게되었습니다. 나는 프로그램이 더 이상 존재하지 않는 고객에게 응답을 다시 보내려고 할 때 그것이 일어나고 있다고 확신합니다.

이것을 다루는 좋은 방법은 무엇입니까? 내가 선호하는 해상도는 단순히 서버 측 연결을 클라이언트에 닫고 전체 프로그램을 종료하기보다는 계속 진행합니다.

추신: 이것 질문/답변은 일반적인 방식으로 문제를 다룹니다. 구체적으로 어떻게 해결해야합니까?

도움이 되었습니까?

해결책

시도 : 문을 읽으십시오.

try:
    # do something
except socket.error, e:
    # A socket error
except IOError, e:
    if e.errno == errno.EPIPE:
        # EPIPE error
    else:
        # Other error

다른 팁

표준 소켓 모듈을 사용하고 있다고 가정하면 socket.error: (32, 'Broken pipe') 예외 (다른 사람들이 제안한 것처럼 ioerror가 아님). 이것은 당신이 설명한 경우, 즉 원격 측면이 연결이 끊어진 소켓으로 보내거나 쓰는 경우가 발생합니다.

import socket, errno, time

# setup socket to listen for incoming connections
s = socket.socket()
s.bind(('localhost', 1234))
s.listen(1)
remote, address = s.accept()

print "Got connection from: ", address

while 1:
    try:
        remote.send("message to peer\n")
        time.sleep(1)
    except socket.error, e:
        if isinstance(e.args, tuple):
            print "errno is %d" % e[0]
            if e[0] == errno.EPIPE:
               # remote peer disconnected
               print "Detected remote disconnect"
            else:
               # determine and handle different error
               pass
        else:
            print "socket error ", e
        remote.close()
        break
    except IOError, e:
        # Hmmm, Can IOError actually be raised by the socket module?
        print "Got IOError: ", e
        break

이 예외는 첫 번째 쓰기에서 닫힌 소켓에 항상 제기되는 것은 아닙니다. 더 일반적으로 두 번째 쓰기 (첫 번째 쓰기에 작성된 바이트 수가 소켓의 버퍼 크기보다 크지 않으면). 응용 프로그램에서 원격 엔드가 이미 연결이 끊어 졌을 때 첫 번째 쓰기로부터 데이터를 수신했다고 생각할 경우이를 명심해야합니다.

사용 하여이 문제를 줄일 수 있지만 완전히 제거 할 수는 없습니다. select.select() (또는 poll). 쓰기를 시도하기 전에 피어에서 읽을 준비가 된 데이터를 확인하십시오. 만약에 select 피어 소켓에서 읽을 수있는 데이터가 있다는 보고서를 사용하여 읽으십시오. socket.recv(). 이것이 빈 문자열을 반환하면 원격 피어가 연결을 닫았습니다. 여기에는 여전히 레이스 조건이 있기 때문에 여전히 예외를 잡아서 처리해야합니다.

Twisted는 이런 종류의 일에 적합하지만 이미 공정한 코드를 작성한 것처럼 들립니다.

SIGPIPE (아마도 당신이 의미한다고 생각하지만 EPIPE?) 소켓을 종료 한 다음 데이터를 보낼 때 소켓에서 발생합니다. 간단한 솔루션은 데이터를 보내기 전에 소켓을 차단하지 않는 것입니다. 이것은 파이프에서도 발생할 수 있지만 네트워크 서버이기 때문에 당신이 겪고있는 것 같지 않습니다.

각 스레드의 일부 최상위 핸들러에서 예외를 포착하는 대역 에이드를 적용 할 수도 있습니다.

물론 사용한 경우 꼬인 각 클라이언트 연결에 대한 새 스레드를 생산하는 대신이 문제가 없을 것입니다. 여러 스레드가 동일한 I/O 채널을 처리하는 경우 닫고 작업을 정확하게 작성하는 것은 정말 어렵습니다 (응용 프로그램에 따라 불가능할 수도 있습니다).

나는 같은 질문에 직면한다. 그러나 다음에 같은 코드를 제출하면 작동합니다. 처음 파산했을 때 :

$ packet_write_wait: Connection to 10.. port 22: Broken pipe

두 번째로 작동합니다.

[1]   Done                    nohup python -u add_asc_dec.py > add2.log 2>&1

그 이유는 현재 서버 환경에 관한 것일 수 있습니다.

내 대답은 S.Lott와 매우 가깝습니다.

try:
    # do something
except IOError, e:
    # ooops, check the attributes of e to see precisely what happened.
    if e.errno != 23:
        # I don't know how to handle this
        raise

여기서 "23"은 Epipe에서 얻은 오류 번호입니다. 이렇게하면 권한 오류 또는 장비가없는 다른 것을 처리하려고 시도하지 않습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top