Il server può utilizzare lo stesso socket per inviare la risposta al client? Come?

StackOverflow https://stackoverflow.com/questions/467396

  •  19-08-2019
  •  | 
  •  

Domanda

Sto usando i socket Berkeley (entrambi: dominio Internet e dominio Unix) e mi chiedevo se il server può usare gli stessi socket per leggere la richiesta e scrivere una risposta al client. O il client dovrebbe creare un altro socket in attesa del replay e il server si connetterà ad esso dopo aver elaborato il messaggio ricevuto.

A proposito, sto parlando di socket orientati alla connessione (stream socket, TCP, ...).

Questo è il codice del server semplificato (Icomit di controllo degli errori sulle chiamate di sistema qui solo per semplicità):

int main() {

    int server_socket, connected_socket;
    struct sockaddr_in server_addr;
    char buf[1024];
    char aux[256];
    int bytes_read;

    server_socket = socket(AF_INET, SOCK_STREAM, 0);    

    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(1234);
    bind(server_socket, &server_addr, sizeof(server_addr))

    listen(server_socket, 5)

    connected_sodket = accept(server_socket, 0, 0);
    do {
        bzero(buf, sizeof(buf));
        bytes_read = read(connected_socket, buf, sizeof(buf));        
    } while (bytes_read > 0);          

    /* Here I want to use connected_socket to write the reply, can I? */

    close(connected_socket);       

    close(server_socket);

    return (EXIT_SUCCESS);
}

E questo è il codice client semplificato (ommendo di controllare l'errore sulle chiamate di sistema qui solo per semplicità):

int main() {

    int client_socket;
    struct sockaddr_in server_addr;

    client_socket = socket(AF_INET, SOCK_STREAM, 0);

    hp = gethostbyname("myhost");
    server_addr.sin_family = AF_INET;
    memcpy(&server_addr.sin_addr, hp->h_addr_list[0], hp->h_length);
    server_addr.sin_port = htons(1234);

    connect(client_socket, &server_addr, sizeof(server_addr));

    write(client_socket, MSG, sizeof(MSG));

    /* Here I want to wait for a response from the server using client_socket, can I? */

    close(client_socket);

    return (EXIT_SUCCESS);
}

Posso usare connected_socket nel server e client_socket nel client per trasmettere un messaggio di risposta? O dovrei usare l'indirizzo client che ottengo nel server quando in " accetta " connettersi a un socket nel client?

Ho provato usando read / wrint nel client / server in cui è mostrato il commento, ma in questo modo entrambi i programmi rimangono bloccati, sembra essere un dead-lock.

Grazie anticipatamente! Saluti.

È stato utile?

Soluzione

Puoi usare lo stesso socket MA il tuo programma è impostato per far leggere il server TUTTO il client che invia prima di provare a rispondere. Quindi il ciclo nel server non verrà completato fino a quando il client non chiuderà il lato di scrittura del suo socket in modo che il server ottenga un EOF (0 byte letti), e quindi il server non invierà mai la sua risposta.

Ci sono un paio di modi in cui puoi gestirlo.

  1. È possibile interrompere il ciclo nel server dopo aver visto l'intera richiesta, anziché leggere fino a EOF. Ciò richiede che i dati inviati dal client siano in qualche modo auto-delimitati, in modo che il server possa sapere quando legge tutto.
  2. È possibile utilizzare una seconda connessione per la risposta. Probabilmente non il migliore.
  3. È possibile utilizzare l'arresto asimmetrico del socket. Chiedi al client di eseguire shutdown (client_socket, SHUT_WR) per chiudere a metà il socket. Il server vedrà quindi l'EOF (e il ciclo finirà), ma l'altra direzione sul socket sarà ancora aperta per la risposta.

Altri suggerimenti

dovresti usare lo stesso socket!

Il protocollo dell'applicazione definisce in modo inequivocabile quando il client e il server devono attendere i dati o scambiarsi messaggi; presupponendo un protocollo con una sola richiesta dal client e una risposta dal server, dovrebbe contenere quanto segue:


  • Il client stabilisce una connessione con il server;
  • il client invia la sua richiesta (con send ());
  • il client sa , in virtù del protocollo, che il server risponderà; quindi attende i dati sullo stesso socket (recv ());
  • dopo aver convalidato la risposta, il client può chiudere il socket.

  • Il server accetta una connessione dal client;
  • il server sa che il primo passo spetta al client, quindi attende i dati (recv ());
  • il server convalida la richiesta;
  • il server ora sa , dal protocollo, che il client è in attesa di dati; quindi invia la sua risposta con send ();
  • il server sa , dal protocollo, che non ci sono ulteriori passaggi; quindi può chiudere il socket.

Sì, è possibile. Guarda questa pagina per un esempio di un server semplice (e client semplice). Tieni presente che il server in genere passa il descrittore di file "accetta" in un nuovo processo in modo che possa continuare ad ascoltare altre connessioni in entrata

Non solo dovresti usare lo stesso socket (come dice Federico), ma in realtà devi per ottenere i pacchetti di ritorno attraverso i firewall.

I firewall sono a conoscenza delle connessioni TCP e consentono automaticamente il passaggio dei dati di ritorno se una macchina all'interno del firewall ha avviato la connessione. Se invece provassi a creare un nuovo socket TCP dall'esterno il firewall lo bloccherebbe a meno che quel traffico non sia stato specificamente permesso.

Sì, i socket SOCK_STREAM sono bidirezionali. Dovresti essere in grado di leggere e scrivere sullo / dallo stesso socket su ciascun lato della connessione. La pagina man per socket (2) contiene maggiori dettagli su questo.

Sì, puoi. I socket TCP sono bidirezionali. Basta usare le stesse funzioni read () e write (). Assicurati anche di verificare le condizioni di errore su tutte le chiamate a connect (), read (), write (), ... poiché non puoi controllare cosa succede sulla rete.

Siamo spiacenti; Non l'ho detto ma l'ho provato in questo modo

Questo codice nel server in cui il commento è:

write(connected_socket, "Ok, I got it", sizeof("Ok, I got it"));

e questo codice nel client in cui il commento è:

read(client_socket, buf, sizeof(buf));

Entrambi i programmi rimangono bloccati e quando uccido il client, il server mostra i messaggi ricevuti (ho un printf subito dopo che il server chiama leggi ).

Lo provo con send e recv (entrambi con 0 flag) invece di leggere e scrivere e non è cambiato.

Nella configurazione corrente il server tenta di leggere fino a quando il client non chiude il socket, mentre il client non chiude il socket fino a quando il server non ha risposto. Pertanto hai una sorta di "deadlock". Il server non si ferma a leggere nella speranza che possano arrivare altri dati e il client non ha modo di dire al server che è stato eseguito.

È necessario che il server riconosca che la richiesta è completa mentre la connessione è ancora aperta. Se, ad esempio, si termina la richiesta con una nuova riga, il server può verificare se ha ricevuto una riga completa, quindi interrompere la lettura e inviare la risposta.

L'hai provato? Sembra che dovrebbe funzionare quando inserisci il codice dove indicato

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top