2010-07-24 24 views
5

के बाद 0 को वापस लौटाएं जब मुझे लिनक्स सॉकेट प्रोग्राम पर काम किया गया तो मुझे चुनिंदा फ़ंक्शन के बारे में कोई समस्या है। चयन फ़ंक्शन ठीक काम करता है क्योंकि मैन पेज कहता है कि क्लाइंट सर्वर द्वारा कॉन्फ़िगर किए गए अंतराल में सर्वर पक्ष से कनेक्ट होता है। यदि टाइमआउट हुआ, तो चयन फ़ंक्शन हमेशा के लिए 0 लौटाएगा। उस समय, मैंने क्लाइंट को डीबग किया और क्लाइंट को सर्वर से कनेक्ट किया था। लेकिन चयन समारोह अभी भी 0 लौटा है। मैंने इस समस्या को खोज लिया है लेकिन कोई उपयोगी नहीं मिला। क्या कोई जान सकता है कि ऐसा क्यों चुना गया? मेरा लिनक्स संस्करण RHEL5.4 है। आपके सहयोग के लिए धन्यवाद।क्यों चुनें() हमेशा पहली बार

कोड नीचे दिखाया गया है।

static const int maxLog = 10000; 

int main() 
{ 
    int servSock; 
    signal(SIGPIPE, SIG_IGN); 
    if((servSock = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
    { 
     printf("socket create fail\n"); 
     exit(-1); 
    } 
    int val = 1; 
    if(setsockopt(servSock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))<0) 
    { 
     DieWithUserMessage("setsockopt error"); 
    } 

    struct sockaddr_in serverAddr; 
    memset(&serverAddr, 0, sizeof(serverAddr)); 
    serverAddr.sin_family = AF_INET; 
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    serverAddr.sin_port = htons(22000); 

    if(bind(servSock, (struct sockaddr *) &serverAddr, 
       sizeof(serverAddr)) < 0) 
    { 
     printf("socket bind fail\n"); 
     exit(-1); 
    } 

    if(listen(servSock, maxLog) < 0) 
    { 
     printf("listen failed\n"); 
     exit(-1); 
    } 

    fd_set read_set; 
    FD_ZERO(&read_set); 
    FD_SET(servSock, &read_set); 
    int maxfd1 = servSock + 1; 
    std::set<int> fd_readset; 

    for(;;){  
     struct timeval tv; 
     tv.tv_sec = 5; 
     int ret = select(maxfd1, &read_set, NULL, NULL, tv);  
     if(ret == 0) 
      continue; 

     if(ret < 0) 
      DieWithUserMessage("select error"); 

     if(FD_ISSET(servSock, &read_set)) 
     { 
      struct sockaddr_in clntAddr; 
      socklen_t clntAddrlen = sizeof(clntAddr); 
      int clntSock = accept(servSock, (struct sockaddr *) &clntAddr, &clntAddrlen); 
      if(clntSock < 0) 
      { 
       printf("accept failed()"); 
       exit(-1); 
      } 

      maxfd1 = 1 + (servSock>=clntSock? servSock:clntSock); 
      FD_SET(clntSock, &read_set); 
      fd_readset.insert(clntSock); 
     } 

    } 
} 
+0

सामान्य सलाह: चयन() के बजाय मतदान() का उपयोग करें। – Dummy00001

+0

आपको 'select' –

उत्तर

19

'select()' फ़ंक्शन उपयोग करने में निराशाजनक है; आपको इसे कॉल करने से पहले हर बार अपने तर्क स्थापित करना होगा क्योंकि यह उन्हें संशोधित करता है। आप जो देख रहे हैं वह एक प्रदर्शन है यदि आप लूप के चारों ओर प्रत्येक बार fd_set (ओं) सेट नहीं करते हैं।

+0

में' टीवी' के बजाय '& tv' का उपयोग करना चाहिए आपकी सहायता के लिए धन्यवाद। जैसा कि आप सुझाव देते हैं, मैं लूप की शुरुआत में fs_set को रीसेट करता हूं और यह ठीक काम करता है। – terry

+1

धन्यवाद! मैं इस – Frederik

+0

पर अपने बालों को फाड़ रहा था आप एक जीवन बचाओ आदमी हैं !!! बहुत बहुत धन्यवाद। –

1

आपको प्रत्येक पुनरावृत्ति पर अपना एफडी_एसईटी भरना होगा। ऐसा करने का सबसे अच्छा तरीका है कि आप अपने एफडी का संग्रह कहीं और बनाए रखें और एक अस्थायी FD_SET में चुनिंदा कॉल के लिए आपको जिसकी आवश्यकता हो।

यदि आपको बहुत से ग्राहकों को संभालने की आवश्यकता है, तो आपको FD_SETSIZE (/usr/include/sys/select.h में) मैक्रो को बदलना पड़ सकता है।

मुबारक नेटवर्क प्रोग्रामिंग :)

3

आप सही जवाब पहले से ही है - select(2) की प्रत्येक कॉल से पहले फिर से init fd_set रों।

मैं आपको एक बेहतर विकल्प के बारे में इंगित करना चाहता हूं - लिनक्स epoll(4) सुविधा प्रदान करता है। हालांकि यह मानक नहीं है, यह अधिक सुविधाजनक है क्योंकि आपको केवल एक बार प्रतीक्षा करने वाली घटनाओं को सेट करने की आवश्यकता है। कर्नेल आपके लिए फाइल डिस्क्रिप्टर इवेंट टेबल प्रबंधित करता है, इसलिए यह अधिक कुशल है। epollएज-ट्रिगर कार्यक्षमता भी प्रदान करता है, जहां एक वर्णक पर राज्य में केवल एक ही संकेत संकेत दिया जाता है।

पूर्णता के लिए - बीएसडी kqueue(2) प्रदान करते हैं, सोलारिस में /dev/poll है।

एक और बात: आपके कोड में क्लाइंट और सर्वर के बीच एक अच्छी तरह से ज्ञात दौड़ स्थिति है। Stevens UnP: Nonblocking accept पर एक नज़र डालें।

+0

'पोलिक्स' में 'पोल' मानकीकृत है। –

+1

लेकिन यह बेहतर नहीं है तो 'चयन करें'। –

1

यदि आप प्रत्येक कॉल का चयन करने से पहले समय रेखा संरचना को रीसेट नहीं करते हैं तो वही प्रभाव होता है।

+0

पीओएसईक्स का कहना है कि 'चयन()' फ़ंक्शन टाइमआउट पैरामीटर को संशोधित कर सकता है।संभवतः, यदि आप उस सिस्टम पर हैं जो इसे संशोधित करता है, तो इसका संशोधित मान टाइमआउट समाप्त होने तक समय शेष रहता है, जो टाइमआउट समाप्त होने पर शून्य होता है, और इसलिए पहले पुनरावृत्ति के बाद कॉल एक मतदान में गिरावट आती है क्योंकि शून्य किए गए टाइमआउट का अर्थ है 'जरूरी होने पर प्रतीक्षा करें' के बजाय 'तुरंत लौटें'। –

0

मुझे अपने समान कोड में एक ही समस्या है। मैंने चयन() को कॉल करने से पहले प्रत्येक बार प्रारंभ करने के सुझाव का पालन किया और यह काम करता है। इस मामले में कोड में, बस दो लाइनों को लूप में लाने से यह काम करेगा।

FD_ZERO(&read_set); 
FD_SET(servSock, &read_set); 
संबंधित मुद्दे