Pergunta

Eu escrevi um servidor de jogos multi-rosca simples em python que cria uma nova thread para cada conexão do cliente. Eu estou achando que a cada momento e, em seguida, o servidor irá falhar devido a um erro-pipe quebrado / SIGPIPE. Tenho certeza de que isso está acontecendo quando as tentativas de programa para enviar uma volta resposta a um cliente que não está mais presente.

O que é uma boa maneira de lidar com isso? Minha definição preferida seria simplesmente fechar a conexão do lado do servidor para o cliente e seguir em frente, em vez de sair todo o programa.

PS: Este pergunta / resposta lida com a problema de uma forma genérica; como especificamente devo resolvê-lo?

Foi útil?

Solução

Leia-se sobre a tentativa:. Declaração

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

Outras dicas

Assumindo que você está usando o módulo tomada padrão, você deve ser captura a exceção socket.error: (32, 'Broken pipe') (não IOError como outros têm sugerido). Este será levantada no caso que você descreveu, ou seja, o envio / escrita a um soquete para o qual o lado remoto foi desligado.

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

Note que esta excepção não vai ser sempre levantada na primeira gravação para um soquete fechado - mais geralmente a segunda gravação (a menos que o número de bytes escritos na primeira gravação é maior do que o tamanho do buffer do socket). Você precisa manter isso em mente no caso de sua aplicação pensa que o fim remoto recebeu os dados da primeira gravação quando ele pode já ter desconectado.

Você pode reduzir a incidência (mas não eliminar totalmente) deste usando select.select() (ou poll). Verificar a existência de dados pronto para ler a partir de pares antes de tentar uma gravação. Se os relatórios select que há dados disponíveis para ler da tomada de pares, lê-lo usando socket.recv(). Se isso retorna uma cadeia vazia, o peer remoto fechou a conexão. Porque ainda há uma condição de corrida aqui, você ainda vai precisar para capturar e tratar a exceção.

torcida é grande para este tipo de coisa, no entanto, parece que você já escreveu um pouco de código.

SIGPIPE (embora eu acho que talvez você EPIPE média?) Ocorre em órbitas quando você desligar um soquete e, em seguida, enviar os dados a ele. A solução mais simples é não fechar o soquete para baixo antes de tentar enviá-lo dados. Isso também pode acontecer em tubos, mas não parece que é o que você está experimentando, já que é um servidor de rede.

Você também pode simplesmente aplicar o band-aid de captura a exceção de alguma manipulador de nível superior em cada segmento.

Claro que, se você usou torcida em vez de gerar um novo thread para cada conexão do cliente, você provavelmente não iria' t tem esse problema. É realmente difícil (talvez impossível, dependendo do aplicativo) para obter a ordenação das operações de perto e escrever corrija se vários segmentos estão lidando com o mesmo canal de I / O.

I enfrentar com a mesma pergunta. Mas eu enviar o mesmo código da próxima vez, ele simplesmente funciona. A primeira vez que ele quebrou:

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

O segundo tempo funciona:

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

Eu acho que a razão pode ser sobre o ambiente atual do servidor.

A minha resposta é muito perto de S. Lott de, exceto eu seria ainda mais especial:

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

, onde "23" é o número de erro que você recebe de EPIPE. Desta forma, você não vai tentar lidar com um erro de permissões ou qualquer outra coisa que você não está equipado para.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top