2012-04-17 13 views
8

से कनेक्ट और डिस्कनेक्ट करें मुझे लिनक्स के लिए एपोल का उपयोग करके टीसीपी क्लाइंट के लिए एसिंक कनेक्ट और डिस्कनेक्ट करने की आवश्यकता है। एक्सटी हैं विंडोज़ में फ़ंक्शंस, जैसे कनेक्टएक्स, डिस्कनेक्टएक्स, AcceptEx, आदि ... टीसीपी सर्वर मानक स्वीकृति समारोह में काम कर रहा है, लेकिन टीसीपी क्लाइंट में कनेक्ट नहीं हो रहा है और डिस्कनेक्ट नहीं हो रहा है ... सभी सॉकेट अनब्लॉकिंग कर रहे हैं।Async एपोल (लिनक्स)

मैं यह कैसे कर सकता हूं?

धन्यवाद!

+0

यह आपको मदद कर सकता है: http://stackoverflow.com/questions/2875002/non-blocking-tcp-connect-with-epoll –

+0

लिंक किए गए डीजेबी पृष्ठ पर सुझावों के संभावित विकल्प के रूप में, मैं सुझाव देना चाहता हूं कि 'डुप्लिकेट' 'और 'डिस्क्रिप्टर' बंद करें (और डुप्लिकेट का उपयोग करें)।परीक्षण नहीं किया गया, लेकिन यह मेरी समझ में काम करना चाहिए। दस्तावेज़ बताते हैं कि यह एक गंभीर प्रोग्रामिंग त्रुटि है जो 'बंद' के वापसी मूल्य की जांच न करें, क्योंकि यह पिछली त्रुटि लौटा सकती है। यही वही है जो आप चाहते हैं (यदि 'बंद' त्रुटि देता है, तो 'कनेक्ट' विफल हुआ)। यद्यपि यदि आप 'एपोल' का उपयोग करते हैं तो आपको एक ओएस रखने की गारंटी है जहां' होकॉकॉप्ट (SO_ERROR) 'काम करेगा ... – Damon

+1

यदि व्यवहार्य है, तो सबसे सरल विकल्प सेट करने से पहले कनेक्ट() रिटर्न के बाद तक प्रतीक्षा करना है NON_BLOCK। – delicateLatticeworkFever

उत्तर

29

एक गैर अवरुद्ध, कनेक्ट() सॉकेट संभालने पहले से ही किया गया है गैर अवरुद्ध करने के लिए:

int res = connect(fd, ...); 
if (res < 0 && errno != EINPROGRESS) { 
    // error, fail somehow, close socket 
    return; 
} 

if (res == 0) { 
    // connection has succeeded immediately 
} else { 
    // connection attempt is in progress 
} 

दूसरे मामले में, जहां कनेक्ट (के लिए) और EINPROGRESS के साथ विफल (केवल इस मामले में), आपको सॉकेट को लिखने योग्य होने की प्रतीक्षा करनी है, उदाहरण के लिए एपोल के लिए निर्दिष्ट करें कि आप इस सॉकेट पर EPOLLOUT की प्रतीक्षा कर रहे हैं।() कभी

int result; 
socklen_t result_len = sizeof(result); 
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &result, &result_len) < 0) { 
    // error, fail somehow, close socket 
    return; 
} 

if (result != 0) { 
    // connection failed; error code is in 'result' 
    return; 
} 

// socket is ready for read()/write() 

मेरे अनुभव में, लिनक्स पर, कनेक्ट: एक बार जब आप सूचित कर दिया है कि यह लिखने योग्य है, कनेक्शन का प्रयास का परिणाम जाँच (epoll साथ, भी प्राप्त करने के लिए एक EPOLLERR या EPOLLHUP घटना की उम्मीद) तुरंत सफल होता है और आपको हमेशा उत्तरदायित्व की प्रतीक्षा करनी पड़ती है। हालांकि, उदाहरण के लिए, फ्रीबीएसडी पर, मैंने गैर-अवरुद्ध कनेक्ट() को लोकहोस्ट को तुरंत सफल होने के लिए देखा है।

+0

यह काम नहीं करता है! – Matt

+0

@ मैट मुझे पता है कि यह करता है, आप शायद यहां कुछ गलत कर रहे हैं। आप वास्तव में क्या प्रयास कर रहे हैं, यह कहां विफल रहा है? क्या आपने सॉकेट को fcntl का उपयोग करके गैर-अवरुद्ध मोड में रखा है? –

+0

ओह, कभी भी ध्यान न दें। मेरे हिस्से पर एक बग। हाँ मेरे पास गैर-अवरुद्ध सॉकेट था। कनेक्ट के परिणाम की जांच करते समय मुझे एक बग था! क्लासिक सी गलती। – Matt

0

मैं एक "पूरा" और मामले किसी में यहाँ का जवाब इस की तलाश में है है:

#include <sys/epoll.h> 
#include <errno.h> 
.... 
.... 
int retVal = -1; 
socklen_t retValLen = sizeof (retVal); 

int status = connect(socketFD, ...); 
if (status == 0) 
{ 
    // OK -- socket is ready for IO 
} 
else if (errno == EINPROGRESS) 
{ 
    struct epoll_event newPeerConnectionEvent; 
    int epollFD = -1; 
    struct epoll_event processableEvents; 
    unsigned int numEvents = -1; 

    if ((epollFD = epoll_create (1)) == -1) 
    { 
     printf ("Could not create the epoll FD list. Aborting!"); 
     exit (2); 
    }  

    newPeerConnectionEvent.data.fd = socketFD; 
    newPeerConnectionEvent.events = EPOLLOUT | EPOLLIN | EPOLLERR; 

    if (epoll_ctl (epollFD, EPOLL_CTL_ADD, socketFD, &newPeerConnectionEvent) == -1) 
    { 
     printf ("Could not add the socket FD to the epoll FD list. Aborting!"); 
     exit (2); 
    } 

    numEvents = epoll_wait (epollFD, &processableEvents, 1, -1); 

    if (numEvents < 0) 
    { 
     printf ("Serious error in epoll setup: epoll_wait() returned < 0 status!"); 
     exit (2); 
    } 

    if (getsockopt (socketFD, SOL_SOCKET, SO_ERROR, &retVal, &retValLen) < 0) 
    { 
     // ERROR, fail somehow, close socket 
    } 

    if (retVal != 0) 
    { 
     // ERROR: connect did not "go through" 
    } 
} 
else 
{ 
    // ERROR: connect did not "go through" for other non-recoverable reasons. 
    switch (errno) 
    { 
    ... 
    } 
} 
+0

मुझे विश्वास है कि epoll_wait() गलत होने के बाद आपकी त्रुटि जांच - आपको हमेशा getockopt के माध्यम से कनेक्शन प्रयास का परिणाम देखना चाहिए (SO_ERROR), भले ही आपको EPOLLERR नहीं मिला। मैन पेज में EINPROGRESS देखें http://linux.die.net/man/2/connect भी, जोर दें() गंभीर त्रुटियों को संभालने का गलत तरीका है - इसका मतलब यह होगा कि आपने * प्रमाणित * किया है कि यह कभी नहीं हो सकता है। इसके बजाय बाहर निकलें() का उपयोग करें, जो एनडीईबीयूजी परिभाषित होने पर भी प्रोग्राम को समाप्त कर देगा। –

+0

बस सुझाए गए संपादन जोड़े गए। अन-संपादित संस्करण मेरे लिए काम करता प्रतीत होता है। – Sonny

2

अनुभव से, जब गैर अवरुद्ध कनेक्शन का पता लगाने, epoll का चयन और चुनाव से थोड़ा अलग है।

epoll साथ

:

बाद कनेक्ट() कॉल किया जाता है, वापसी कोड की जाँच करें।

यदि कनेक्शन तुरंत पूरा नहीं किया जा सकता है, तो एपोल के साथ EPOLLOUT ईवेंट पंजीकृत करें।

कॉल epoll_wait()।

यदि कनेक्शन विफल हुआ, तो आपकी घटनाएं EPOLLERR या EPOLLHUP से भरेंगी, अन्यथा EPOLLOUT ट्रिगर हो जाएगा।

+0

हाँ, मैं अपने जवाब में उल्लेख करना भूल गया था कि एपोल EPOLLOUT के अलावा EPOLLERR या EPOLLHUP को वापस कर सकता है। उल्लेख करने के लिए धन्यवाद, यह सही है। –

1

मैंने सोनी के समाधान की कोशिश की है और epoll_ctl अमान्य तर्क वापस कर देगा। तो मैं शायद लगता है कि यह इस प्रकार है करने के लिए सही रास्ता:

1. बनाएँ socketfd और epollfd

2.Use epoll_ctl socketfd और epoll घटना के साथ epollfd संबद्ध करने के लिए।

3.do कनेक्ट (socketfd, ...)

वापसी मान 4.Check

या errno

5. यदि errno == EINPROGRESS, epoll_wait कर