2013-11-23 8 views
6

Ich habe einen Client mit dem Server verbunden (TCP-Verbindung). In dem Fall, wenn der Server abstürzt (ich trenne ihn), muss mein Client mit einem anderen Server verbunden sein, um den Dienst fortzusetzen. Aber wenn der erste Server zurückkommt, muss ich den Client erneut mit ihm verbinden. Ich konnte meinen Client mit dem Sicherungsserver verbinden, nachdem der erste Server abgestürzt ist, aber ich habe ein Problem damit, meinen Client wieder mit dem ersten Server zu verbinden. Ich habe eine Funktion create_newconnect() für die Wiederverbindung mit dem Server, aber es funktioniert nicht (deshalb ich rufe es nicht im Code) Ich habe versucht, mein Programm zu vereinfachen, so viel wie ich konnte, so wäre es nicht zu groß Dies ist eine Client-SeiteWiederherstellung der Verbindung zum Server nach dem Absturz

#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

Es wäre hilfreich zu wissen, was für Sie nicht funktioniert und die Diagnose, die Sie sehen. Ich kann eine Reihe von Problemen im Code feststellen, aber die Implementierung gegen einen von mir implementierten Testdienst kann Ihre Probleme möglicherweise nicht beheben. Hat Ihre reale Situation, dass der Client und der Primär- und der Backup-Server alle auf demselben Host liegen, oder ist das ein Artefakt Ihrer Testversion? Möchten Sie, dass dieses Testprogramm repariert wird oder Antworten auf die Frage gibt, wie Sie das ursprüngliche Problem eines Clients beheben können, der automatisch zwischen primären und Backup-Servern ausfällt? – gwaigh

Antwort

6

denke ich, das erste, was wirst du betrachten müssen, ist: nach dem ersten Server auf den Backup-Server und Ihren Kunden erfolgreich wieder angeschlossen abgestürzt ist, wie würde Ihr Kunde weiß schon, dass der erste Server wieder online ist?

Ich kann mir zwei Möglichkeiten vorstellen: Man könnte sein, dass der Backup-Server den Client über das Wiederauftreten des Primärservers informiert (zB durch Senden einer Art PRIMARY_SERVER_ONLINE-Nachricht über die TCP-Verbindung oder einfach durch Schließen die TCP-Verbindung mit der Erwartung, dass der Client versuchen würde, erneut eine Verbindung zum primären Server herzustellen). Der andere Ansatz besteht darin, Ihren Client so intelligent zu machen, dass er in regelmäßigen Abständen (z. B. einmal pro Minute) versucht, die Verbindung zum Primärserver wiederherzustellen, selbst wenn er die TCP-Verbindung zum Sicherungsserver verwendet. Das ist machbar, aber nicht mit einem einzigen Thread und Blockieren von I/O wie Ihr geposteten Code hat ... (weil, wenn Ihr Programm in einem recv() Anruf blockiert ist, gibt es keine Möglichkeit, etwas anderes zu tun, wie zu versuchen verbinde eine TCP-Verbindung). Sie müssen entweder nicht blockierende E/A verwenden und() (oder ähnlich) oder asynchrone E/A oder mehrere Threads auswählen, um dies ordnungsgemäß durchzuführen.

+1

Aus der Sicht der Bandbreite ist die erste Option mit ziemlicher Sicherheit besser. Auf diese Weise rufen nur die Backup-Server den primären Server ab. Wird Ihr primärer Server nicht mehr synchronisiert, sobald er wieder verfügbar ist? In diesem Fall muss möglicherweise mit dem Backup gesprochen werden, bevor der Dienst wiederhergestellt wird. Wenn nicht, sind Ihre Server im Grunde zustandslos? Wenn ja, warum hast du eine primäre und eine Sicherung ... sie sind nur Peers. In diesem Fall sollten Sie versuchen, die Clients aus Lastgründen zwischen ihnen zu halten und die Belastung zu verringern, wenn ein Fehler auftritt. – Speed8ump

+0

@ JeremyFriesner Ich werde zweiten Ansatz versuchen, was ich denke, dass ich versuchen werde, eine Verbindung mit dem Hauptserver, bevor ich eine Nachricht an den Backup-Server senden. Außerdem können Sie mehr über das Blockieren von I/O herausfinden, das ich habe, das ist mir nicht wirklich vertraut. Danke – swiftk

+0

@swiftk Sockets werden standardmäßig im Blocking-Modus erstellt, was bedeutet, dass, wenn send()/recv() nicht gesendet/empfangen werden kann, der send()/recv() -Aufruf nicht möglich ist zurückkommen, bis einige Daten gesendet/empfangen wurden (dh möglicherweise nicht für lange Zeit). Wenn Sie lieber möchten, dass diese Aufrufe nie blockieren (dh, Ihr Thread kann etwas anderes tun, während Sie darauf warten, dass der Socket zum Senden/Empfangen bereit ist), können Sie den Socket nach dem Erstellen in den nicht blockierenden Modus versetzen , über fcntl (fd, F_SETFL, O_NONBLOCK); oder unter Windows ist es unsigned long m = 1; ioctlsocket (fd, FIONBIO, &m); –

0

Ihr Programm ruft nach dem Verbindungsaufbau rekursiv tcp() auf. Dies ist mit ziemlicher Sicherheit nicht korrekt und führt bei jeder Trennung zu Ressourcen (hauptsächlich Stack).

Sie müssen vermeiden, dass der Code den Socket-Dateideskriptor (Sockfd) nach Wert an die Funktionen übergibt, da er sich nach jeder neuen Verbindung ändert.

Grundsätzlich können Sie eine Liste von (zwei oder mehr) Hosts in der Reihenfolge ihrer Präferenz haben. Versuchen Sie dann immer, Verbindungen zu denen herzustellen, die eine höhere Präferenz haben als diejenige, mit der Sie gerade verbunden sind. Wenn eine Verbindung hergestellt ist, schließen Sie alle anderen geöffneten Sitzungen und wechseln Sie zur neuen bevorzugten Verbindung.

Halten Sie diese gekapselt und lassen Sie die aktuelle aktive Sockfd für die Verwendung von allen anderen Funktionen zurück.

Verwandte Themen