2012-06-05 8 views
19

मैं जैसे एक कॉल द्वारा बनाई AF_UNIX सॉकेट की एक जोड़ी के साथ एक जोड़ी अजीब बातें दिखाई दे रही है:AF_UNIX सॉकेट ओवरहेड?

socketpair(AF_UNIX, SOCK_STREAM, 0, sfd); 

कहाँ SFD किसी पूर्णांक फ़ाइल वर्णनकर्ता के लिए [2] सरणी है।

सबसे पहले, डिफ़ॉल्ट बफर आकार/proc/sys/net (जैसे wmem_default जो 128K पर सेट है) के बजाय बिल्कुल 122K (124928 बाइट्स) लगता है। क्या किसी को इस अजीब बफर आकार का कारण पता है?

दूसरा, सॉकेट (8 बाइट्स) के माध्यम से छोटे संदेश लिखते समय दूसरा। मैं केवल लिखने वाले ब्लॉक से पहले 423 लिख सकता हूं, जो केवल 8 * 423 = 3384 बाइट्स है, एक और अजीब आकार है। संदेश इस तरह काम कर रहे हैं कि वे प्रत्येक 2 9 5 + छोटे बाइट्स ले रहे हैं। इस उपर का स्रोत क्या है?

RHEL6 (2.6.32, 64-बिट) पर चल रहा है

मैं उपरि लागत की तुलना करने के डेटा के विभिन्न आकारों की कोशिश करने के लिए एक कार्यक्रम लिखा है:

#include <errno.h> 
#include <stdio.h> 
#include <stdint.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 

#define DATA_SIZE 4 

void run(size_t size) { 
    int sfd[2]; 
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sfd) == -1) { 
     perror("error"); 
    } 


    int sndbuf, sbsize = sizeof(sndbuf); 
    getsockopt(sfd[0], SOL_SOCKET, SO_SNDBUF, &sndbuf, (socklen_t*)&sbsize); 

    printf("Data Size: %zd\n", size); 
    char buff[size]; 
    size_t wrote=0; 
    for (size_t ii=0; ii < 32768; ii++) { 
     if ((send(sfd[0], buff, size, MSG_DONTWAIT) == -1) && (errno == EAGAIN)) { 
      wrote = ii; 
      break; 
     } 
    } 

    printf("Wrote:  %zd\n", wrote); 

    if (wrote != 0) { 
     int bpm = sndbuf/wrote; 
     int oh = bpm - size; 

     printf("Bytes/msg: %i\n", bpm); 
     printf("Overhead: %i\n", oh); 
     printf("\n"); 
    } 

    close(sfd[0]); close(sfd[1]); 
} 

int main() { 
    int sfd[2]; 
    socketpair(AF_UNIX, SOCK_STREAM, 0, sfd); 

    int sndbuf, sbsize = sizeof(sndbuf); 
    getsockopt(sfd[0], SOL_SOCKET, SO_SNDBUF, &sndbuf, (socklen_t*)&sbsize); 

    printf("Buffer Size: %i\n\n", sndbuf); 
    close(sfd[0]); close(sfd[1]); 

    for (size_t ii=4; ii <= 4096; ii *= 2) { 
     run(ii); 
    } 
} 

कौन देता है:

Buffer Size: 124928 

Data Size: 4 
Wrote:  423 
Bytes/msg: 295 
Overhead: 291 

Data Size: 8 
Wrote:  423 
Bytes/msg: 295 
Overhead: 287 

Data Size: 16 
Wrote:  423 
Bytes/msg: 295 
Overhead: 279 

Data Size: 32 
Wrote:  423 
Bytes/msg: 295 
Overhead: 263 

Data Size: 64 
Wrote:  423 
Bytes/msg: 295 
Overhead: 231 

Data Size: 128 
Wrote:  348 
Bytes/msg: 358 
Overhead: 230 

Data Size: 256 
Wrote:  256 
Bytes/msg: 488 
Overhead: 232 

Data Size: 512 
Wrote:  168 
Bytes/msg: 743 
Overhead: 231 

Data Size: 1024 
Wrote:  100 
Bytes/msg: 1249 
Overhead: 225 

Data Size: 2048 
Wrote:  55 
Bytes/msg: 2271 
Overhead: 223 

Data Size: 4096 
Wrote:  29 
Bytes/msg: 4307 
Overhead: 211 

एक पाइप का उपयोग कर वर्सस निश्चित रूप से बहुत अधिक ओवरहेड है:

Data Size: 4 
Wrote:  16384 
Bytes/msg: 4 
Overhead: 0 

Data Size: 8 
Wrote:  8192 
Bytes/msg: 8 
Overhead: 0 

Data Size: 16 
Wrote:  4096 
Bytes/msg: 16 
Overhead: 0 

Data Size: 32 
Wrote:  2048 
Bytes/msg: 32 
Overhead: 0 

Data Size: 64 
Wrote:  1024 
Bytes/msg: 64 
Overhead: 0 

Data Size: 128 
Wrote:  512 
Bytes/msg: 128 
Overhead: 0 

Data Size: 256 
Wrote:  256 
Bytes/msg: 256 
Overhead: 0 

Data Size: 512 
Wrote:  128 
Bytes/msg: 512 
Overhead: 0 

Data Size: 1024 
Wrote:  64 
Bytes/msg: 1024 
Overhead: 0 

Data Size: 2048 
Wrote:  32 
Bytes/msg: 2048 
Overhead: 0 

Data Size: 4096 
Wrote:  16 
Bytes/msg: 4096 
Overhead: 0 
+0

भेजें() वास्तव में लिखित बाइट्स की संख्या देता है। आपको यह मानना ​​चाहिए कि यह सब कुछ लिखा गया था। – EJP

+1

सबसे खराब मामला मैं जो दावा कर रहा हूं उससे कम लिखा होगा, जो डोमेन सॉकेट पर ओवरहेड को और भी बदतर बना देगा। –

उत्तर

1

क्या आपने net.unix.max_dgram_qlen sysctl का मान देखा है?

कर्नेल अधिकतम उड़ान में AF_UNIX डेटाग्राम पर एक सीमा लगाता है। मेरी प्रणाली पर सीमा वास्तव में बहुत कम है: केवल 10.

+0

मुझे इसके बारे में पता नहीं था, नहीं। क्या यह यहां लागू होगा, क्योंकि मैं एक सॉक्रम्रीम प्रकार गा रहा हूं? –

+1

नहीं, यह केवल कम से कम कर्नेल संस्करण पर, डेटाग्राम सॉकेट पर लागू होना चाहिए। –

+1

असल में, मैं नहीं देख सकता कि wmem_max को मारने पर यूनिक्स डेटाग्राम सॉकेट लिखना कभी कम क्यों होगा। –

5

सॉकेट (7) मैन पेज पर एक नज़र डालें। एक अनुभाग है जो पढ़ता है:

SO_SNDBUF अधिकतम सॉकेट बाइट्स में बफर भेजता है या प्राप्त करता है। कर्नेल इस मान (बुककीपिंग ओवरहेड के लिए स्थान की अनुमति देने के लिए) को दोगुना करता है जब यह सेटॉकोपट (2) का उपयोग करके सेट किया जाता है, और यह दोगुना मान getsockopt (2) द्वारा वापस किया जाता है। डिफ़ॉल्ट मान /proc/sys/net/core/wmem_default फ़ाइल द्वारा सेट किया गया है और अधिकतम अनुमत मान /proc/sys/net/core/wmem_max फ़ाइल द्वारा सेट किया गया है। इस विकल्प के लिए कम से कम (दोगुनी) मूल्य 2048.

तो ऐसा लगता है कि भूमि के ऊपर कर्नेल के लिए जानकारी बहीखाता धारण करने के लिए बस है।

+0

मुझे यह भी यकीन नहीं है कि स्थानीय सॉकेट पर लागू होता है, और उपलब्ध बफर स्पेस का एक सरल छिद्रण अभी भी देखे जाने वाले सभी ओवरहेड के लिए जिम्मेदार नहीं होगा। –

+1

मैन पेज AF_UNIX या गैर स्थानीय डोमेन के बीच अंतर नहीं करता है, इसलिए मुझे लगता है कि यह बोर्ड पर लागू होता है। यही वह दस्तावेज है जिसे मैं स्थिति के बारे में ढूंढने में सक्षम हूं। मुझे संदेह है कि आपको "बिल्कुल" पता होना चाहिए कि आपके लिए ओवरहेड का उपयोग करने के लिए कर्नेल नेटवर्किंग कोड को देखना होगा। – Chimera

+1

मैंने इस जवाब को स्वीकार नहीं किया है क्योंकि मुझे लगता है कि दो ओवरहेड के कारक के साथ भी, मैं अभी भी प्रति संदेश बहुत अधिक रास्ता देख रहा हूं। यहां तक ​​कि अगर कर्नेल केवल मुझे 62464 बाइट्स का उपयोग करने दे रहा था, तो मुझे बफर भरने से पहले 15000+ संदेश लिखने में सक्षम होना चाहिए, और मैं केवल 1/30 देख रहा हूं। –

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