2013-11-23 13 views
6

私はクライアントをサーバーに接続しています(TCP接続)。サーバがクラッシュした場合(私はそれを切断します)、サービスを続けるためにクライアントを別のサーバに接続する必要があります。しかし、最初のサーバーが復帰したら、クライアントを再接続する必要があります。 最初のサーバーがクラッシュした後、クライアントをバックアップサーバーに接続できましたが、クライアントを最初のサーバーに再接続する際に問題があります。私はサーバに再接続するための関数create_newconnect()を作ったが、それは動作しない(それがなぜコードで呼び出されないのだろう) できるだけプログラムを単純化しようとしたので、あなたの最初のサーバがクラッシュしたし、あなたのクライアントが正常にバックアップサーバに再接続した後、どのようにお使いになります。大きな にこれは、私はあなたが考慮する必要があるとしている最初のものだと思うクライアント側クラッシュ後にサーバーへの接続を復元します。

#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

あなたとあなたが見る診断のためにうまくいかないことを知ることは役に立ちます。私はコード内でいくつかの問題を見ることができますが、私が実装したテストサービスに対して動作させることは、あなたの問題に対処できないかもしれません。あなたの実際の状況は、クライアントとプライマリサーバとバックアップサーバの両方がすべて同じホストに存在するのでしょうか、それともテストバージョンの成果物ですか?このテストプログラムを修正したいのですか、プライマリサーバーとバックアップサーバーの間で自動的に失敗するクライアントの元の問題を解決する方法についての回答はありますか? – gwaigh

答えて

6

ですクライアントは、最初のサーバがオンラインに戻ったことを知っていますか?

バックアップサーバーがプライマリサーバーの再表示についてクライアントに通知する可能性があります(たとえば、TCP接続経由で何らかのPRIMARY_SERVER_ONLINEメッセージを送信するなど)クライアントがプライマリサーバに再度接続しようとすると予想されるTCP接続)。

クライアントをスマートにして、バックアップサーバーへのTCP接続を使用している間でも定期的に(1分に1回)プライマリサーバーに再接続を試みることができます。これは実行可能ですが、単一のスレッドではなく、投稿されたコードのようなI/Oをブロックしていません...(あなたのプログラムがrecv()呼び出しでブロックされている場合、試してみる方法はありませんTCP接続を接続する)。正常に動作させるには、ノンブロッキングI/Oとselect()(または類似)、または非同期I/O、または複数のスレッドを使用する必要があります。

+1

帯域幅の観点から、最初の選択肢はほぼ確実です。そうすれば、バックアップサーバーだけがプライマリサーバーをポーリングします。プライマリサーバが復旧したら同期が外れますか?もしそうなら、とにかくサービスを復元する前に、バックアップに話しかける必要があります。あなたのサーバーは基本的にステートレスですか?もしそうなら、なぜあなたはプライマリとバックアップを持っていますか?彼らは単なる同僚です。そのような場合は、負荷の理由からクライアントを分散させ、障害が発生したときに負荷を軽減する必要があります。 – Speed8ump

+0

@JeremyFriesner私は、バックアップサーバーにメッセージを送信する前に、メインサーバーに接続しようとしていると思います。また、私が持っているI/Oのブロックについてもっと詳しく説明することができます。私はそれに精通していません。ありがとう – swiftk

+0

@swiftkソケットはデフォルトでブロッキングモードで作成されます。つまり、send()/ recv()が呼び出された時点でデータを送信できない場合、send()/ recv()いくつかのデータが送受信されるまで返されます(つまり、おそらく長い間)。これらの呼び出しが決してブロックされないようにしたい場合(つまり、ソケットがsend/recvの準備ができるのを待っている間にあなたのスレッドが何か他のことをすることができるように)、ソケットを作成した後に非ブロックモードに設定することができます、fcntl(fd、F_SETFL、O_NONBLOCK)を介して。 Windowsではunsigned long m = 1; ioctlsocket(fd、FIONBIO、&m); –

0

プログラムは再接続後にtcp()を再帰的に呼び出します。これはほぼ間違いなく、各切断時にリソース(主にスタック)が使用されることになります。

ソケットファイルディスクリプタ(sockfd)を新しい接続ごとに変更される関数に値渡しすることを避ける必要があります。

一般的な原則として、(2つ以上の)ホストのリストを優先順に並べることができます。次に、現在接続しているものより高い優先度を持つものへの接続を常に作成しようとします。次に、接続が確立されたら、開いている他のすべてのセッションを閉じ、新しい優先接続に切り替えます。

これをカプセル化したままにしておき、他のすべての機能で使用するために現在のアクティブなsockfdを返すようにします。

関連する問題