मेरे पास एक बहु-थ्रेडेड सर्वर (थ्रेड पूल) है जो 20 धागे का उपयोग करके बड़ी संख्या में अनुरोध (एक नोड के लिए 500/सेकेंड तक) को संभाला जा रहा है। एक श्रोता धागा है जो आने वाले कनेक्शन स्वीकार करता है और उन्हें हैंडलर थ्रेड के लिए प्रक्रिया करने के लिए कतार देता है। एक बार प्रतिक्रिया तैयार हो जाने के बाद, धागे क्लाइंट को लिखते हैं और सॉकेट बंद करते हैं। सभी हाल ही में ठीक होने लगते थे, प्रतिक्रिया परीक्षण के बाद एक टेस्ट क्लाइंट प्रोग्राम यादृच्छिक रूप से लटकना शुरू कर दिया। खुदाई के बाद, ऐसा लगता है कि सर्वर से बंद() वास्तव में सॉकेट को डिस्कनेक्ट नहीं कर रहा है। मैंने फाइल डिस्क्रिप्टर नंबर के साथ कोड में कुछ डिबगिंग प्रिंट जोड़े हैं और मुझे इस प्रकार का आउटपुट मिलता है।बंद() सॉकेट को ठीक से बंद नहीं कर रहा है
Processing request for 21
Writing to 21
Closing 21
करीब() 0 का वापसी मूल्य 0 है, या कोई अन्य डीबग कथन मुद्रित होगा। लटकने वाले क्लाइंट के साथ इस आउटपुट के बाद, lsof एक स्थापित कनेक्शन दिखा रहा है।
सर्वर 8160 21u आईपीवी 4 32,754,237 टीसीपी स्थानीय होस्ट जड़: 9980-> स्थानीय होस्ट: 47,530 (स्थापित)
ग्राहक 17,747 12U आईपीवी 4 32,754,228 टीसीपी स्थानीय होस्ट जड़: 47530-> स्थानीय होस्ट: 9980 (स्थापित)
यह रूप में है यदि सर्वर क्लाइंट को शटडाउन अनुक्रम कभी नहीं भेजता है, और यह स्थिति तब तक लटकती है जब तक क्लाइंट की मौत नहीं हो जाती है, सर्वर की तरफ से प्रतीक्षा करें स्थिति
सेवर 8160 रूट 21u आईपीवी 4 32754237 टीसीपी लोकलहोस्ट: 9980-> लोकलहोस्ट: 47530 (CLOSE_WAIT)
यदि ग्राहक के पास टाइमआउट निर्दिष्ट है, तो यह लटकने की बजाए टाइमआउट होगा। मैं मैन्युअल रूप से
call close(21)
सर्वर में gdb से सर्वर में चला सकता है, और क्लाइंट फिर डिस्कनेक्ट हो जाएगा। यह शायद 50,000 अनुरोधों में हो सकता है, लेकिन विस्तारित अवधि के लिए ऐसा नहीं हो सकता है।
लिनक्स संस्करण: 2.6.21.7-2.fc8xen Centos संस्करण: 5.4 (अंतिम)
सॉकेट कार्रवाई इस प्रकार हैं
सर्वर:
पूर्णांक client_socket; संरचना sockaddr_in client_addr; socklen_t client_len = sizeof (client_addr);
while(true) {
client_socket = accept(incoming_socket, (struct sockaddr *)&client_addr, &client_len);
if (client_socket == -1)
continue;
/* insert into queue here for threads to process */
}
तब थ्रेड सॉकेट उठाता है और प्रतिक्रिया बनाता है।
/* get client_socket from queue */
/* processing request here */
/* now set to blocking for write; was previously set to non-blocking for reading */
int flags = fcntl(client_socket, F_GETFL);
if (flags < 0)
abort();
if (fcntl(client_socket, F_SETFL, flags|O_NONBLOCK) < 0)
abort();
server_write(client_socket, response_buf, response_length);
server_close(client_socket);
server_write और server_close।
void server_write(int fd, char const *buf, ssize_t len) {
printf("Writing to %d\n", fd);
while(len > 0) {
ssize_t n = write(fd, buf, len);
if(n <= 0)
return;// I don't really care what error happened, we'll just drop the connection
len -= n;
buf += n;
}
}
void server_close(int fd) {
for(uint32_t i=0; i<10; i++) {
int n = close(fd);
if(!n) {//closed successfully
return;
}
usleep(100);
}
printf("Close failed for %d\n", fd);
}
ग्राहक:
क्लाइंट साइड उपयोग कर रहा है libcurl वी 7.27.0
CURL *curl = curl_easy_init();
CURLcode res;
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, write_tag);
res = curl_easy_perform(curl);
कुछ भी नहीं फैंसी, बस एक बुनियादी कर्ल कनेक्शन। क्लाइंट tranfer.c में लटकता है (libcurl में) क्योंकि सॉकेट को बंद होने के रूप में नहीं माना जाता है। यह सर्वर से अधिक डेटा की प्रतीक्षा कर रहा है।SO_LINGER स्थापना 1 सेकंड
struct linger l;
l.l_onoff = 1;
l.l_linger = 1;
if (setsockopt(client_socket, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) == -1)
abort();
इन में जबरन बंद करने के लिए कोई फर्क नहीं बना दिया है पास
shutdown(fd, SHUT_WR);
char buf[64];
while(read(fd, buf, 64) > 0);
/* then close */
से पहले
शटडाउन:
चीजें मैं अब तक की कोशिश की है। किसी भी विचार की बहुत प्रशंसा की जाएगी।
संपादित करें - यह एक कतार पुस्तकालय के अंदर एक थ्रेड-सुरक्षा समस्या होने के कारण समाप्त हो गया है जिससे सॉकेट को कई धागे से अनुपयुक्त तरीके से संभाला जा सकता है।
क्या आप 100% सकारात्मक हैं, कोई अन्य थ्रेड संभवतः सॉकेट का उपयोग कर सकता है जब आप उस पर 'बंद' कहते हैं? आप अपने गैर-अवरुद्ध पढ़ने को कैसे करते हैं? –
मुझे डर है कि मैंने अभी यहां लॉग इन किया है और इस मुद्दे को याद किया है। मुझे बाद में पता चला कि आसपास के कनेक्शन पास करने के लिए उपयोग की जाने वाली कतार में एक थ्रेड सुरक्षा समस्या थी। यहां कोई बग नहीं था। गलत जानकारी के लिए खेद है। – DavidMFrey