2013-11-23 22 views
6

Ho un client connesso al server (connessione TCP). Nel caso in cui il server si blocchi (lo disconnetto), il mio client deve essere connesso a un altro server, al fine di continuare il servizio. Ma quando ritorna il primo server, devo ricollegare il client nuovamente. Sono riuscito a connettere il mio client al server di backup dopo il primo arresto anomalo del server, ma ho un problema con la riconnessione del mio client al primo server. Ho creato una funzione per la riconnessione al server, create_newconnect(), ma non funziona (è per questo che non lo chiamo nel codice) Ho provato a semplificare il mio programma il più possibile, quindi non sarebbe stato al grande Questo è un lato clientripristinare la connessione al server dopo l'arresto anomalo

#include <stdlib.h> 
#include <stdio.h> 
#include <ctype.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <signal.h> 
#include <string.h> 
#include <arpa/inet.h> 
#include <time.h> 
#define SIZE sizeof(struct sockaddr_in) 


struct sockaddr_in server; 
void tcp_protocol();//execute client tcp protocol 
void server_check(); 
void tcp(); 
void create_newconnect(); 

int main (int argc, char *argv[]) 
{ 

    int portno; 

    //Test for correct number of arguments 
    if (argc != 3) 
    { 
     fprintf(stderr, "Usage: %s Port# IP Address \n", argv[0]); 
     exit(1); 
    } 
    portno = atoi(argv[1]);//convert port # to int 
    server.sin_family = AF_INET; 
    server.sin_port = htons(portno); 
    server.sin_addr.s_addr = inet_addr(argv[2]);//use client ip address 
    tcp();//call tcp function 
    return 0; 
} 
void tcp() 
{ 
    int sockfd; 
    char c ; 
    //create socket 
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0))==-1) 
    { 
     perror ("socket call faild"); 
     exit (1); 
    } 
    //connect to the server 
    if (connect (sockfd, (struct sockaddr *)&server, SIZE)==-1) 
    { 
     perror ("connect call faild"); 
     exit (1); 
    } 
    while(1) 
    { 
    printf("Enter char\n"); 
    scanf("%c",&c); 
     server_check(sockfd); 
     //send packet to server 
     if (send(sockfd, &c, sizeof(c),0)<0) 
     { 
     printf("error sending\n"); 
     } 
     //if packet is received from server 
     if(recv(sockfd, &c, sizeof(c),0)>0) 
     { 
      printf("server's respond %c\n", c);//print result 
     } 
    } 
close(sockfd); 
} 


void server_check(int sock) 
{ 
    char b ='b'; 
    //send packet to server 
    if (send(sock, &b, sizeof(b),0)<0) 
     printf("error sending\n"); 
    //if packet is received from server 
    if((recv(sock, &b, sizeof(b),0)>0)) 
    { 
     printf("server responded\n"); 

    } 
    else//if server is not responding 
    { 
    printf("server crashed\n"); 
     close(sock);//close socket 
     server.sin_port = htons(5002); 
     server.sin_addr.s_addr = inet_addr("127.0.0.1"); 
     tcp();//create new connection 
    } 


} 
void create_newconnect() 
{ 
    int newsockfd; 
    server.sin_port = htons(5001); 
    //create socket 
    if ((newsockfd = socket(AF_INET, SOCK_STREAM, 0))==-1) 
    { 
     perror ("socket call faild"); 
     exit (1); 
    } 
    //connect to the server 
    if (connect (newsockfd, (struct sockaddr *)&server, SIZE)==-1) 
    { 
     perror ("connect call faild"); 
     exit (1); 
    } 
     tcp();//call function to execute tcp protocol 

} 
+1

Sarebbe utile sapere cosa non funziona per te e la diagnostica che vedi. Posso vedere una serie di problemi nel codice, ma farlo funzionare contro un servizio di test che ho implementato potrebbe non risolvere i tuoi problemi. La tua situazione reale ha il client e sia il server principale che quello di backup si trovano tutti nello stesso host o è un artefatto della versione di prova? Stai cercando di risolvere questo programma di test o hai trovato risposte su come risolvere il problema originale di un client che si guasta automaticamente tra server primari e server di backup? – gwaigh

risposta

6

Penso che la prima cosa che si sta andando a prendere in considerazione è: dopo il primo server è andato in crash e il vostro cliente ha ricollegato con successo al server di backup, come sarebbe la vostra il cliente ha mai saputo che il primo server è tornato online?

Sono in grado di pensare a due possibilità: uno potrebbe essere che il server di backup potrebbe notificare al client la ricomparsa del server primario (ad esempio inviando una sorta di messaggio PRIMARY_SERVER_ONLINE sulla connessione TCP, o forse semplicemente chiudendo la connessione TCP, con l'aspettativa che ciò provocherebbe di nuovo il tentativo del client di connettersi al server primario).

L'altro approccio sarebbe quello di rendere il client abbastanza intelligente da poter periodicamente (ad esempio una volta al minuto) provare a riconnettersi al server primario anche mentre sta utilizzando la connessione TCP al server di backup. Ciò è fattibile, ma non con un singolo thread e bloccando I/O come il tuo codice postato ha ... (perché se il tuo programma è bloccato in una chiamata recv(), non c'è modo che faccia qualcos'altro come provare a collegare una connessione TCP). Dovresti utilizzare l'I/O non bloccante e selezionare() (o simile), I/O asincrono o più thread, per farlo correttamente.

+1

Dal punto di vista dell'ampiezza di banda, la prima opzione è quasi certamente migliore. In questo modo solo i server di backup stanno eseguendo il polling sul server primario. Il tuo server primario non sarà più sincronizzato una volta tornato? In tal caso potrebbe essere necessario parlare al backup prima che ripristini comunque il servizio. In caso contrario, i tuoi server sono fondamentalmente privi di stato? Se è così, perché hai un primario e un backup ... sono solo coetanei. In tal caso dovresti cercare di mantenere i client distribuiti tra loro per ragioni di carico e per alleggerire la tensione quando si fallisce. – Speed8ump

+0

@JeremyFriesner Proverò il secondo approccio, quello che penso è che proverò a connettermi al server principale prima di inviare un messaggio al server di backup. Puoi anche approfondire l'argomento sul blocco dell'I/O che ho, non mi è molto familiare. Grazie – swiftk

+0

I socket @swiftk vengono creati in modalità di blocco per impostazione predefinita, il che significa che se non possono inviare/ricevere dati al momento viene chiamato send()/recv(), quindi la chiamata send()/recv() non verrà ritorno fino a quando non ci sono alcuni dati inviati/ricevuti (cioè, eventualmente, non per molto tempo). Se preferisci che quelle chiamate non si blocchino mai (cioè che il thread possa fare qualcos'altro mentre stai aspettando che il socket sia pronto per l'invio/recv), puoi impostare il socket in modalità non bloccante dopo averlo creato , tramite fcntl (fd, F_SETFL, O_NONBLOCK); o sotto Windows è unsigned long m = 1; ioctlsocket (fd, FIONBIO, &m); –

0

Il programma chiama in modo ricorsivo tcp() dopo la riconnessione. Questo è quasi certamente non corretto e comporterà l'utilizzo di risorse (principalmente stack) su ogni disconnessione.

È necessario evitare che il codice passi il descrittore del file del socket (sockfd) in base al valore delle funzioni, poiché cambierà dopo ogni nuova connessione.

Come principio generale, è possibile avere un elenco di (due o più) host in ordine di preferenza. Quindi, in ogni momento, cerca di creare connessioni con quelle che hanno una preferenza maggiore di quella con cui hai attualmente una connessione. Quindi, quando viene stabilita una connessione, chiudere tutte le altre sessioni aperte e passare alla nuova connessione preferita.

Mantenere questo incapsulato e restituire l'attuale sockfd attivo per l'utilizzo da parte di tutte le altre funzioni.

Problemi correlati