Pergunta

Estou implementando um serviço simples usando datagramas mais de unix sockets locais (AF_UNIX família de endereços, ou seja, não UDP ). O servidor está vinculado a um endereço público, e recebe solicitações muito bem. Infelizmente, quando se trata de responder de volta, sendto falha a menos que o cliente é obrigado também. (O erro comum é Transport endpoint is not connected).

A ligação a algum nome aleatório (sistema de arquivos com base ou abstrato) funciona. Mas eu gostaria de evitar que: quem sou eu para garantir os nomes que eu escolhi não vai colidir

documentação modo de fluxo Os sockets Unix nos dizem que um nome abstrato será atribuído a eles no momento connect se não tiver um já. É tal recurso disponível para um datagrama sockets orientados?

Foi útil?

Solução

Eu suponho que você está executando Linux; Eu não sei se este conselho se aplica a SunOS ou qualquer UNIX.

Em primeiro lugar, a resposta: depois do socket () e antes do sendto connect () ou () Primeiro, tente adicionar este código:

struct sockaddr_un me;
me.sun_family = AF_UNIX;
int result = bind(fd, (void*)&me, sizeof(short));

Agora, a explicação: o unix (7) página homem diz o seguinte:

Quando um socket está ligado e não já tem um endereço local um endereço exclusivo no resumo namespace serão gerados automaticamente.

Infelizmente, a página homem mentiras.

código fonte do Linux , vemos que unix_dgram_connect () só chama unix_autobind () se SOCK_PASSCRED está situado nas bandeiras de soquete. Desde que eu não sei o que SOCK_PASSCRED é, e agora é 1:00 AM, eu preciso olhar para outra solução.

unix_bind , percebo que as chamadas unix_bind unix_autobind se o passado-de tamanho é igual a "sizeof (short)". Assim, a solução acima.

Boa sorte, e bom dia.

Rob

Outras dicas

O unix (7) página homem que eu referenciado tinha esta informação sobre AutoBind soquetes UNIX :

Se a ligação (2) de chamada especifica addrlen como sizeof (sa_family_t), ou a opção de soquete SO_PASSCRED foi especificado para um encaixe que não foi explicitamente ligado a um endereço, em seguida, o encaixe é autobound para um endereço de resumo.

É por isso que verifica o Linux Kernel do endereço comprimento é igual a sizeof (short), porque sa_family_t é uma curta. O outro (7) página homem unix referenciado por grande resposta de Rob diz que soquetes de cliente são sempre autobound em conectar, mas porque soquetes SOCK_DGRAM são sem conexão (apesar de chamar connect sobre eles) eu acredito que isso só se aplica a sockets SOCK_STREAM.

Observe também que quando o fornecimento de seus próprios nomes abstratos soquete namespace, endereço do socket neste espaço de nomes é dado pelos bytes adicionais em sun_path que são cobertos pelo comprimento especificado da estrutura de endereço.

struct sockaddr_un me;
const char name[] = "\0myabstractsocket";
me.sun_family = AF_UNIX;
// size-1 because abstract socket names are not null terminated
memcpy(me.sun_path, name, sizeof(name) - 1);
int result = bind(fd, (void*)&me, sizeof(me.sun_family) + sizeof(name) - 1);

sendto () devem também limitar o comprimento de endereço, e não passar sizeof (sockaddr_un).

Um pouco de uma resposta tardia, mas para quem acha isso usando o google como eu fiz. A resposta de Rob Adam me ajudou a obter a resposta 'real' para isso:. simplesmente usar set (SO_SOCKET nível, consulte man 7 unix) para definir SO_PASSCRED para 1. Não há necessidade de um ligamento bobo

Eu usei isso em PHP, mas ele não tem SO_PASSCRED definido (PHP estúpido). Ele ainda funciona, embora, se você defini-lo sozinho. No meu computador que tem o valor de 16, e eu acho que ele vai trabalhar bastante portável.

Eu não estou tão certo de que eu entendi sua pergunta completamente, mas aqui é uma implementação de datagrama de um servidor de eco Eu só escreveu. Você pode ver o servidor está respondendo ao cliente no mesmo IP / PORT foi enviado.

Aqui está o código

Primeiro, o servidor (ouvinte)

from socket import *
import time
class Listener:
    def __init__(self, port):
        self.port = port
        self.buffer = 102400

    def listen(self):

        sock = socket(AF_INET, SOCK_DGRAM)
        sock.bind(('', self.port))

        while 1:
            data, addr = sock.recvfrom(self.buffer)
            print "Received: " + data
            print "sending to %s" % addr[0]
            print "sending data %s" % data
            time.sleep(0.25)
            #print addr # will tell you what IP address the request came from and port
            sock.sendto(data, (addr[0], addr[1]))
            print "sent"
        sock.close()

if __name__ == "__main__":
    l = Listener(1975)
    l.listen()

E agora, o Cliente (remetente) que recebe a resposta do ouvinte

from socket import *
from time import sleep
class Sender:
    def __init__(self, server):
       self.port = 1975
       self.server = server
       self.buffer = 102400

    def sendPacket(self, packet):
        sock = socket(AF_INET, SOCK_DGRAM)
        sock.settimeout(10.75)


        sock.sendto(packet, (self.server, int(self.port)))

        while 1:
            print "waiting for response"
            data, addr = sock.recvfrom(self.buffer)
            sock.close()
            return data



if __name__ == "__main__":
        s = Sender("127.0.0.1")
        response = s.sendPacket("Hello, world!")
        print response
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top