2012-05-25 20 views
5

मैं अपने क्लाइंट और सर्वर के लिए अवरुद्ध टीसीपी सॉकेट का उपयोग कर रहा हूं। जब भी मैं पढ़ता हूं, मैं पहले जांच करता हूं कि select का उपयोग कर स्ट्रीम पर डेटा उपलब्ध है या नहीं। मैं हमेशा एक समय में 40 बाइट्स पढ़ और लिखता हूं। जबकि अधिकांश पढ़ते हैं कुछ मिलीसेकंड या उससे कम लेते हैं, कुछ बस आधे सेकेंड से अधिक लेते हैं। मुझे पता है कि सॉकेट पर डेटा उपलब्ध है।बहुत धीमी सॉकेट पढ़ने का कारण क्या हो सकता है?

मैं भी TCP_NODELAY

यह क्या कारण हो सकता है का उपयोग कर रहा हूँ?

संपादित 2

मैं प्रत्येक पैकेट भेजे और प्राप्त के लिए टाइमस्टैम्प का विश्लेषण किया और देखा कि इस देरी से होता है केवल जब ग्राहक से पहले अगले ऑब्जेक्ट सर्वर ने लिखा है वस्तु को पढ़ने के लिए कोशिश करता है। उदाहरण के लिए, सर्वर ने ऑब्जेक्ट नंबर x लिखा था और इसके बाद क्लाइंट ऑब्जेक्ट एक्स को पढ़ने की कोशिश करने से पहले ऑब्जेक्ट एक्स को पढ़ने की कोशिश कर रहा था, इससे पहले कि सर्वर ऑब्जेक्ट नंबर x + 1 लिखना शुरू कर सके। इससे मुझे संदेह होता है कि सर्वर की ओर से कुछ प्रकार का सहवास हो रहा है।

संपादित

सर्वर 3 अलग बंदरगाहों पर सुन रहा है। ग्राहक इन बंदरगाहों में से प्रत्येक को एक-एक करके जोड़ता है।

तीन कनेक्शन हैं: एक जो सर्वर से क्लाइंट को अक्सर कुछ डेटा भेजता है। एक दूसरा जो क्लाइंट से सर्वर पर डेटा भेजता है। और तीसरा एक जिसका उपयोग डेटा के एकल बाइट भेजने के लिए बहुत ही कम होता है। मुझे पहले कनेक्शन के साथ समस्या का सामना करना पड़ रहा है। मैं select() का उपयोग कर जांच कर रहा हूं कि डेटा उस कनेक्शन पर उपलब्ध है और फिर जब मैं 40 बाइट पढ़ता हूं, तो मुझे लगता है कि उस पढ़ने के लिए लगभग आधे सेकेंड लिया गया था।

कैसे प्रोफ़ाइल को यह बहुत उपयोगी

हो लिनक्स पर जीसीसी का उपयोग करेगा के रूप में किसी भी संकेत दिए गए।

rdrr_server_start(void) {
int rr_sd; int input_sd; int ack_sd; int fp_sd;

startTcpServer(&rr_sd, remote_rr_port); startTcpServer(&input_sd, remote_input_port); startTcpServer(&ack_sd, remote_ack_port); startTcpServer(&fp_sd, remote_fp_port);

connFD_rr = getTcpConnection(rr_sd); connFD_input = getTcpConnection(input_sd); connFD_ack= getTcpConnection(ack_sd); connFD_fp=getTcpConnection(fp_sd); }

static int getTcpConnection(int sd) { socklen_t l en;
struct sockaddr_in clientAddress; len = sizeof(clientAddress); int connFD = accept(sd, (struct sockaddr*) &clientAddress, &len); nodelay(connFD); fflush(stdout); return connFD; }

static void startTcpServer(int *sd, const int port) { *sd= socket(AF_INET, SOCK_STREAM, 0); ASSERT(*sd>0);

// Set socket option so that port can be reused int enable = 1; setsockopt(*sd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int));

struct sockaddr_in a; memset(&a,0,sizeof(a)); a.sin_family = AF_INET; a.sin_port = port; a.sin_addr.s_addr = INADDR_ANY; int bindResult = bind(*sd, (struct sockaddr *) &a, sizeof(a)); ASSERT(bindResult ==0); listen(*sd,2); } static void nodelay(int fd) { int flag=1; ASSERT(setsockopt(fd, SOL_TCP, TCP_NODELAY, &flag, sizeof flag)==0); }

startTcpClient() { connFD_rr = socket(AF_INET, SOCK_STREAM, 0); connFD_input = socket(AF_INET, SOCK_STREAM, 0); connFD_ack = socket(AF_INET, SOCK_STREAM, 0); connFD_fp= socket(AF_INET, SOCK_STREAM, 0);

struct sockaddr_in a; memset(&a,0,sizeof(a)); a.sin_family = AF_INET; a.sin_port = remote_rr_port; a.sin_addr.s_addr = inet_addr(remote_server_ip);

int CONNECT_TO_SERVER= connect(connFD_rr, &a, sizeof(a)); ASSERT(CONNECT_TO_SERVER==0) ;

a.sin_port = remote_input_port; CONNECT_TO_SERVER= connect(connFD_input, &a, sizeof(a)); ASSERT(CONNECT_TO_SERVER==0) ;

a.sin_port = remote_ack_port; CONNECT_TO_SERVER= connect(connFD_ack, &a, sizeof(a)); ASSERT(CONNECT_TO_SERVER==0) ;

a.sin_port = remote_fp_port; CONNECT_TO_SERVER= connect(connFD_fp, &a, sizeof(a)); ASSERT(CONNECT_TO_SERVER==0) ;

nodelay(connFD_rr); nodelay(connFD_input); nodelay(connFD_ack); nodelay(connFD_fp); }

+0

से/डेटा आने से पहले मुझे लगता है कि इस समस्या से संबंधित हार्डवेयर है मिल गया ... – Jah

+0

** एक ग्राहक **, क्या आकार हम कर रहे हैं करने के लिए सर्वर से अक्सर कुछ डेटा भेजता है के बारे में बातें कर रहे हैं? – tuxuday

+0

शायद TCP_NODELAY (Nagle अक्षम करने) एक बुरा विकल्प है, कई लघु क्षेत्रों में जिसके परिणामस्वरूप, भेजे जाने के लिए प्रति "तार्किक" पैकेट कई राउंड ट्रिप में जिसके परिणामस्वरूप है। इसके अलावा आवेदन कार्यक्रम के पक्ष में बहुत सारे सिस्टमकॉल। – wildplasser

उत्तर

0

एक ग्राहक और कई कनेक्शन?

कुछ सॉकेट फ़ंक्शन आपके निष्पादन को अवरुद्ध कर रहे हैं (यानी कार्यों के परिणाम की प्रतीक्षा कर रहे हैं)। मैं प्रत्येक कनेक्शन के लिए एक नया धागा (सर्वर पक्ष पर) खोलने का सुझाव दूंगा ताकि वे एक दूसरे के साथ हस्तक्षेप नहीं कर सकें ...

लेकिन मैं अंधेरे में शूटिंग कर रहा हूं; आपको कुछ अतिरिक्त जानकारी भेजने की आवश्यकता होगी ...

+0

मैंने अपने प्रश्न में कुछ विस्तार जोड़ा है। – AnkurVj

+0

मुझे यकीन नहीं है कि आपकी समस्या वहां मौजूद है, लेकिन आपको शायद अपने स्टार्ट टीसीपी सर्वर/getTcpConnection फ़ंक्शंस को पुनर्व्यवस्थित करना चाहिए। startTcpServer को सुनने के लिए एक कॉल() है जो प्रोग्राम निष्पादन को अवरुद्ध कर देगा जब तक कि नया कनेक्शन नहीं बनाया जाता। उसके बाद आपको नया कनेक्शन स्वीकार करना चाहिए और आगे बढ़ना चाहिए, लेकिन आपके पास अभी तक एक और कॉल है TcpServer => एक और सुनो ... (सभी एक ही थ्रेड पर) तो आने वाले कनेक्शन को स्वीकार करने के बजाय, आपकी सॉकेट सुनती है (लेकिन किसी अन्य फ़ंक्शन में) ... शायद उन्हें पुनर्व्यवस्थित करें: startTcpServer(); getTcpConnection(); startTcpServer(); getTcpConnection(); ? – Ivica

+0

मुझे लगता है कि 'सुनो() 'ब्लॉक नहीं है? केवल 'स्वीकार करें()' आईएमओ करता है! – AnkurVj

0

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

केवल सर्वर को एक से अधिक वर्णक (सॉकेट) और प्रक्रिया की निगरानी करने की अनुमति देता है, जिसमें डेटा उपलब्ध है। ऐसा नहीं है कि यह समानांतर में प्रसंस्करण करता है। इसके लिए आपको कई धागे या प्रक्रियाओं की आवश्यकता है।

+0

वास्तव में, सर्वर ने एक ही ग्राहक से तीन अलग-अलग बंदरगाहों पर कनेक्शन स्वीकार किए। आदर्श रूप से प्रत्येक कनेक्शन को दूसरे से अलग किया जाना चाहिए। – AnkurVj

+0

क्या आप अपना कोड पेस्ट कर सकते हैं जो तीन अलग-अलग सर्वर सॉकेट बनाने का दिखाता है और यह चुनने के लिए गुज़र रहा है? – fayyazkl

0

शायद यह timeout तर्क से संबंधित कुछ है।

आप select कॉल की timeout तर्क के लिए क्या सेट करूँ?

एक बड़ा एक के लिए समय समाप्ति तर्क बदल सकते हैं और विलंबता निरीक्षण करने के लिए प्रयास करें। कभी-कभी बहुत छोटा टाइमआउट और अक्सर सिस्टम कॉल वास्तव में थ्रूपुट को मार सकता है। शायद आप बेहतर परिणाम प्राप्त कर सकते हैं यदि आप थोड़ा बड़ा विलंबता मानते हैं, तो यह प्राप्य है।

मैं टाइमआउट या कुछ कोड बग संदेह है।

+0

30 मिलीसेकंड – AnkurVj

+0

क्या आप 'चयन' पर कॉल के साथ कोड को 'चयन' और 'read' रिटर्न के बाद सॉकेट से पढ़ सकते हैं? –

+0

@AkkurVj क्यों? यह एक अद्भुत शॉर्ट टाइमआउट है। शायद आप प्रोसेसर के भूख से मर रहे हैं। एक चयन() टाइमआउट आमतौर पर कम से कम कुछ सेकंड होता है। आपको क्या करना है जो हर 30 एमएमएस में किया जाना है? – EJP

1

मैं कोड की इस पंक्ति पर शक होगा:

ASSERT(setsockopt(fd, SOL_TCP, TCP_NODELAY, &flag, sizeof flag)==0); 

आप एक रिलीज निर्माण चला रहे हैं, तो ASSERT ज्यादातर संभावना कुछ भी नहीं करने के लिए परिभाषित किया गया है, तो कॉल वास्तव में नहीं किया जाएगा। Setockopt कॉल ASSERT कथन में नहीं होना चाहिए। इसके बजाय, वापसी मूल्य (एक चर में) वापसी मूल्य में सत्यापित किया जाना चाहिए। Asserts with side effects आम तौर पर एक बुरी बात है। तो अगर यह समस्या नहीं है, तो शायद इसे बदला जाना चाहिए।

+0

ओह मैंने वास्तव में एएसएसईआरटी भाग नहीं दिखाया है जो मेरे कोड में परिभाषित किया गया है। यह बढ़िया काम करता है। – AnkurVj

+1

यह कोड अभी भी काउंटर-बेवकूफ है; साइड इफेक्ट्स के साथ कोड डालने के रूप में 'एएसएसईआरटी' नामक मैक्रो के तर्क के रूप में पाठकों को बहुत भ्रमित किया जाता है, जो मानते हैं कि यह गैर-डीबग बिल्डों पर नहीं चलता है। –

+0

@ अंकुर वीजे: यहां तक ​​कि अगर आपको लगता है कि यह ठीक है, तो आप जोर से कॉल को हटाने का प्रयास कर सकते हैं। ऐसा नहीं है कि मैं आपकी क्षमताओं पर संदेह कर रहा हूं, लेकिन यह दुर्लभ है कि कोई भी पहली बार एएसएसईआरटी मैक्रो लिखता है। –

0

आप कर्नेल एक्सटेंशन GRO, GSO और TSOethtool रूप से अक्षम के साथ TCP_CORK (CORK'ed मोड) का उपयोग कर कोशिश कर सकते हैं:

  • TCP_CORK चिह्नित किये सत्र के अंदर भेजने यह सुनिश्चित करेंगे कि डेटा आंशिक में नहीं भेजा जाएगा सेगमेंट

  • generic-segmentation-offload अक्षम करने, generic-receive-offload और tcp-segmentation-offload यह सुनिश्चित करेगा कि कर्नेल अतिरिक्त एकत्र करने के लिए कृत्रिम देरी नहीं पेश करेगा टीसीपी खंडों यूज़रस्पेस

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