2013-11-23 9 views
6

मेरे पास एक क्लाइंट सर्वर (टीसीपी कनेक्शन) से जुड़ा हुआ है। जब सेवा जारी रखने के लिए सर्वर क्रैश हो जाता है (मैं इसे डिस्कनेक्ट करता हूं) तो मेरे क्लाइंट को किसी अन्य सर्वर से कनेक्ट करने की आवश्यकता होती है। लेकिन जब पहला सर्वर वापस आता है, तो मुझे क्लाइंट को फिर से कनेक्ट करने की आवश्यकता होती है। पहले सर्वर क्रैश होने के बाद मैं अपने क्लाइंट को बैक अप सर्वर से कनेक्ट करने में सक्षम था, लेकिन मुझे अपने क्लाइंट को पहले सर्वर से दोबारा जोड़ने में समस्या है। मैंने सर्वर से पुनः कनेक्ट करने के लिए 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

मुझे लगता है कि पहली बात पर विचार करने के लिए जा रहे हैं है: अपने पहले सर्वर क्रैश हो गया है के बाद ही अपने ग्राहक को सफलतापूर्वक बैकअप सर्वर से पुन: कनेक्ट किया गया है, कैसे होगा आपके क्लाइंट को कभी पता है कि पहला सर्वर लाइन पर वापस आ गया है?

मैं दो संभावनाओं के बारे में सोच सकता हूं: एक ऐसा हो सकता है कि बैकअप सर्वर क्लाइंट को प्राथमिक सर्वर की पुन: उपस्थिति के बारे में सूचित कर सकता है (उदाहरण के लिए टीसीपी कनेक्शन पर किसी प्रकार का PRIMARY_SERVER_ONLINE संदेश भेजकर, या शायद बस बंद करके टीसीपी कनेक्शन, उम्मीद के साथ कि क्लाइंट को प्राथमिक सर्वर से कनेक्ट करने का प्रयास करने का कारण होगा)।

दूसरा दृष्टिकोण आपके क्लाइंट को पर्याप्त रूप से स्मार्ट बनाना होगा (जैसे प्रति मिनट) बैकअप सर्वर से टीसीपी कनेक्शन का उपयोग करते समय भी प्राथमिक सर्वर से पुनः कनेक्ट करने का प्रयास करें। यह करने योग्य है, लेकिन एक ही थ्रेड के साथ नहीं और आपके पोस्ट कोड की तरह I/O अवरुद्ध करना है ... (क्योंकि यदि आपका प्रोग्राम किसी आरईवी() कॉल में अवरुद्ध है, तो ऐसा करने का कोई तरीका नहीं है जैसे कि कोशिश करें एक टीसीपी कनेक्शन कनेक्ट करें)। आपको इसे ठीक से करने के लिए या तो गैर-अवरुद्ध I/O का चयन करना होगा और() (या समान), या एसिंक्रोनस I/O, या एकाधिक थ्रेड का चयन करना होगा।

+1

बैंडविड्थ परिप्रेक्ष्य से पहला विकल्प लगभग निश्चित रूप से बेहतर है। इस तरह केवल बैकअप सर्वर प्राथमिक सर्वर मतदान कर रहे हैं। बैक अप आने के बाद आपका प्राथमिक सर्वर सिंक हो जाएगा? यदि ऐसा है तो इसे बैकअप से बात करने से पहले इसे फिर से सेवा बहाल करने की आवश्यकता हो सकती है। यदि नहीं तो आपके सर्वर मूल रूप से स्टेटलेस हैं? यदि ऐसा है तो आपके पास प्राथमिक और बैकअप क्यों है ... वे सिर्फ साथियों हैं। उस स्थिति में आपको लोड कारणों से ग्राहकों के बीच वितरित रखने की कोशिश करनी चाहिए और जब कोई विफल रहता है तो तनाव को कम करने के लिए प्रयास करना चाहिए। – Speed8ump

+0

@ जेरेमी फ़्रीज़नर मैं दूसरा दृष्टिकोण आज़माउंगा, मुझे लगता है कि बैक अप सर्वर पर संदेश भेजने से पहले मैं मुख्य सर्वर से कनेक्ट करने का प्रयास करूंगा। इसके अलावा आप I/O को अवरुद्ध करने पर अधिक विस्तार कर सकते हैं, मैं इसके साथ वास्तव में परिचित नहीं हूं। धन्यवाद – swiftk

+0

@ स्विफ्ट सॉकेट डिफ़ॉल्ट रूप से अवरुद्ध मोड में बनाए जाते हैं, जिसका अर्थ यह है कि अगर वे इस समय भेजते हैं/recv डेटा भेज नहीं सकते हैं()/recv() को भेजा जाता है, तो भेजें()/recv() कॉल नहीं होगा तब तक लौटाएं जब तक कुछ डेटा भेजा/प्राप्त न हो (यानी संभवतः लंबे समय तक नहीं)। यदि आप चाहते हैं कि उन कॉलों को कभी भी अवरुद्ध न करें (यानी आपका धागा कुछ और कर सकता है, जबकि आप सॉकेट को भेजने/आरआरवी के लिए तैयार होने की प्रतीक्षा कर रहे हैं), तो आप इसे बनाने के बाद सॉकेट को गैर-अवरुद्ध मोड में सेट कर सकते हैं , fcntl (fd, F_SETFL, O_NONBLOCK) के माध्यम से; या विंडोज के तहत यह हस्ताक्षर किए गए लंबे एम = 1 है; ioctlsocket (एफडी, FIONBIO, &m); –

0

आपका प्रोग्राम दोबारा जुड़ने के बाद tcp() पर दोबारा कॉल करता है। यह लगभग निश्चित रूप से सही नहीं है और परिणामस्वरूप प्रत्येक डिस्कनेक्शन पर संसाधन (मुख्य रूप से ढेर) का उपयोग किया जाएगा।

आपको कोड को सॉकेट फ़ाइल डिस्क्रिप्टर (सॉकफ़्ड) पास करने के लिए कार्य करने के लिए आवश्यक है क्योंकि यह प्रत्येक नए कनेक्शन के बाद बदल जाएगा।

एक सामान्य सिद्धांत के रूप में, आपके पास वरीयता के क्रम में (दो या अधिक) होस्ट की एक सूची हो सकती है। फिर, हर समय उन लोगों के साथ कनेक्शन बनाने का प्रयास करें जिनके पास वर्तमान में कनेक्शन है, उससे अधिक वरीयता है। फिर, जब कोई कनेक्शन स्थापित होता है, तो अन्य सभी खुले सत्र बंद करें, और नए पसंदीदा कनेक्शन पर स्विच करें।

इस encapsulated रखें और इसे अन्य सभी कार्यों द्वारा उपयोग के लिए वर्तमान सक्रिय sockfd वापस कर दिया है।

संबंधित मुद्दे