लिनक्स: क्या टाइमआउट के साथ सॉकेट से कोई रीड या रिकव है?


105

मैं टाइमआउट के साथ सॉकेट से डेटा पढ़ने की कोशिश कैसे कर सकता हूं? मुझे पता है, चयन, pselect, poll, में एक टाइमआउट फ़ील्ड है, लेकिन उनमें से tcp रेनो स्टैक में "tcp फास्ट-पथ" को निष्क्रिय करता है।

एकमात्र विचार मुझे एक पाश में recv (fd, ..., MSG_DONTWAIT) का उपयोग करना है


थ्रेड्स का उपयोग करने का एक विकल्प भी है :) लेकिन थ्रेड सिग्नल की अभी भी जरूरत है
ओएसजीएक्स

जवाबों:


189

आप संचालन प्राप्त करने के समय पर सेट करने के लिए सेटस्कॉपटॉप फ़ंक्शन का उपयोग कर सकते हैं :

SO_RCVTIMEO

समयबाह्य मान सेट करता है जो इनपुट फ़ंक्शन की पूर्ण होने तक अधिकतम समय निर्दिष्ट करता है। यह सेकंड की संख्या के साथ एक समयबद्ध संरचना को स्वीकार करता है और माइक्रोसेकंड की सीमा को निर्दिष्ट करता है कि इनपुट ऑपरेशन को पूरा करने के लिए कितने समय तक इंतजार करना है। यदि अतिरिक्त डेटा प्राप्त किए बिना इस ऑपरेशन को बहुत अधिक समय के लिए अवरुद्ध कर दिया गया है, तो यह कोई डेटा प्राप्त नहीं होने पर [EAGAIN] या [EWOULDBLOCK] पर सेट एक आंशिक गणना या ग़लती के साथ वापस आ जाएगा। इस विकल्प के लिए डिफ़ॉल्ट शून्य है, जो इंगित करता है कि एक प्राप्त संचालन समय से बाहर नहीं होगा। यह विकल्प एक समयबद्ध संरचना लेता है। ध्यान दें कि सभी कार्यान्वयन इस विकल्प को सेट करने की अनुमति नहीं देते हैं।

// LINUX
struct timeval tv;
tv.tv_sec = timeout_in_seconds;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);

// WINDOWS
DWORD timeout = timeout_in_seconds * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);

// MAC OS X (identical to Linux)
struct timeval tv;
tv.tv_sec = timeout_in_seconds;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);

कथित तौर पर विंडोज पर यह कॉल करने से पहले किया जाना चाहिए bind। मैंने प्रयोग द्वारा सत्यापित किया है कि यह bindलिनक्स या ओएस एक्स पर पहले या बाद में किया जा सकता है।


1
इस जवाब ने मेरी गांड को बचा लिया। मैं उस दृढ़ "चयन" बकवास को लागू कर रहा था, जिसमें कोई सफलता नहीं थी। यह तुरंत काम किया, इतना सरल।
21o में 21

अब यही कारण है कि विंडोज़ पर टाइमआउट काम नहीं कर रहा है क्योंकि मैं लिनक्स के लिए कोड का उपयोग कर रहा हूं। धन्यवाद। यदि विंडोज़ का उपयोग नहीं किया जा रहा है, struct timeval tv;तो क्या इसका मतलब है () भी काम नहीं करेगा? मैंने अपने चुनिंदा () कोड को विंडोज़ में पोर्ट करने की कोशिश की और यह तुरंत टाइमआउट हो गया, ऐसा लग रहा है कि मैं इसकी कीमत को नजरअंदाज कर रहा हूं, जिसे मैं समय-समय पर सेट कर रहा हूं।
कूची

1
मैंने 5 सेकंड के लिए टाइमआउट मान निर्धारित किया है। यह हमेशा आने वाले डेटा की परवाह किए बिना प्रत्येक पढ़ने के चक्र के लिए 5 सेकंड क्यों लेता है या नहीं?
हान

यह बाइंड ऑपरेशन के बाद भी खिड़कियों पर काम करता है। विंडोज़ 10 पर कोशिश की
cahit beyaz

1
@ user463035818 यह उत्तर दावा नहीं करना चाहिए।
टॉमेमीस

22

C में recvउपयोग करके अपने फ़ंक्शन में समय जोड़ने के लिए कुछ सरल कोड यहां दिए गए हैं poll:

struct pollfd fd;
int ret;

fd.fd = mySocket; // your socket handler 
fd.events = POLLIN;
ret = poll(&fd, 1, 1000); // 1 second for timeout
switch (ret) {
    case -1:
        // Error
        break;
    case 0:
        // Timeout 
        break;
    default:
        recv(mySocket,buf,sizeof(buf), 0); // get your data
        break;
}

यह अपेक्षा के अनुरूप काम नहीं करेगा। pollकम से कम एक बाइट या टाइमआउट प्राप्त करने के लिए प्रतीक्षा करेंगे, जबकि recvफ़ंक्शन को कॉल करते समय यह sizeof(buf)बाइट्स की प्रतीक्षा करेगा , जिससे यह फिर से अवरुद्ध हो जाएगा यदि यह गिनती अभी तक नहीं आई है, लेकिन इस बार बिना टाइमआउट के।
LoPiTaL

0

// WINDOWS के लिए बाइंड ऑपरेशन के बाद भी काम करता है

DWORD timeout = timeout_in_seconds * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);

-1

के लिए एक हैंडलर स्थापित करें SIGALRM, फिर एक नियमित ब्लॉकिंग से पहले alarm()या उपयोग करें । यदि अलार्म बंद हो जाता है, तो सेट के साथ एक त्रुटि वापस आ जाएगी ।ualarm()recv()recv()errnoEINTR


8
अलार्म (और संकेत) इस कार्य का गलत तरीका है। अगर मुझे tcp तेज पथ का उपयोग करना है, तो मुझे न्यूनतम विलंबता की आवश्यकता है। सिग्नल धीमे हैं।
ऑग्क्स

2
@osgx सिग्नल तभी होता है जब कोई टाइमआउट होता है।
डेविड श्वार्ट्ज

-4

लिनक्स

struct timeval tv;
tv.tv_sec = 30;        // 30 Secs Timeout
tv.tv_usec = 0;        // Not init'ing this can cause strange errors
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv,sizeof(struct timeval));

खिड़कियाँ

DWORD timeout = SOCKET_READ_TIMEOUT_SEC * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));

नोट : आपने bind()उचित रन के लिए फ़ंक्शन कॉल से पहले इस सेटिंग को रखा है


4
इस सवाल का जवाब सालों पहले ही दिया जा चुका है। आपका समाधान क्या नया मूल्य लाता है?
मैकीज जुरेस्को

आपने इस सेटिंग को बाइंड से पहले रखा है () उचित रन के लिए फ़ंक्शन कॉल इस भाग का उल्लेख नहीं है ans में
विवेक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.