2009-10-20 23 views
6

मेरे पास एक पर्ल स्क्रिप्ट है जो फ़ाइलों की सूची के बारे में जानकारी एकत्र करने के लिए बाहरी उपकरण (क्लीयरूल) का उपयोग करती है। मैं आईपीसी उपयोग करने के लिए प्रत्येक फ़ाइल के लिए एक नई प्रक्रिया को उत्पन्न करने से बचना चाहते हैं:मैं विंडोज पर एक गैर-अवरुद्ध आईपीसी कैसे पढ़ूं?

use IPC::Open2; 
my ($cin, $cout); 
my $child = open2($cout, $cin, 'cleartool'); 

आदेश है कि वापस जाने के एकल लाइनों में अच्छी तरह से काम करते हैं। जैसे

print $cin "describe -short $file\n"; 
my $description = <$cout>; 

आदेश है कि कई पंक्तियों लौटने मुझे कैसे एक अवरुद्ध द्वारा काट दिया हो रही बिना पूरे प्रतिक्रिया का उपभोग करने के लिए एक मरे हुए अंत में है पढ़ें:

print $cin "lshistory $file\n"; 
# read and process $cout... 

मैं के लिए filehandle स्थापित करने के लिए कोशिश की है गैर अवरुद्ध fcntl के माध्यम से पढ़ता है:

use Fcntl; 
my $flags = ''; 
fcntl($cout, F_GETFL, $flags); 
$flags |= O_NONBLOCK; 
fcntl($cout, F_SETFL, $flags); 

लेकिन Fcntl संदेश के साथ मर जाता है "आपका विक्रेता निर्धारित नहीं किया Fcntl मैक्रो F_GETFL।"

मैंने $cout->blocking(0) सेट करने के लिए IO :: हैंडल का उपयोग करने का प्रयास किया है, लेकिन यह विफल रहता है (यह undef देता है और $! को "अज्ञात त्रुटि" पर सेट करता है)।

मैं डेटा उपलब्ध हो, तो पढ़ने के लिए प्रयास करने से पहले select उपयोग करने के लिए निर्धारित करने के लिए कोशिश की है:

my $rfd = ''; 
vec($rfd, fileno($cout), 1) = 1; 
while (select($rfd, undef, undef, 0) >= 0) { 
    my $n = read($cout, $buffer, 1024); 
    print "Read $n bytes\n"; 
    # do something with $buffer... 
} 

लेकिन यह है कि कभी भी कुछ भी पढ़ने के बिना लटकी हुई है। क्या कोई जानता है कि यह काम कैसे करें (विंडोज़ पर)?

+0

आईओ पर अवरुद्ध न होने पर आप क्या करने की योजना बना रहे हैं? – jrockway

+0

मैं तब तक पढ़ना चाहता हूं जब तक कि मैं डेटा प्राप्त करना बंद नहीं कर पाता, जो यह निर्धारित करने के प्रयास से अधिक विश्वसनीय प्रतीत होता है कि मैं डेटा को पार्स करके अंत तक पहुंच गया हूं जिसे मैंने पहले ही पुनर्प्राप्त कर लिया है। (डेटा में यह "आखिरी पंक्ति" संकेत नहीं है।) –

+0

किसी संबंधित समस्या के लिए चारों ओर खोजना, मुझे गिटहब पर यह प्रतिबद्धता मिली, जो एक गैर-अवरुद्ध सॉकेट बनाने के लिए काले जादू का आह्वान करता है: https: // github .com/kthakore/frozen-bubble/commit/735dd2307455e32c69827e013992c2d022cb7347 –

उत्तर

5

select only works on sockets विंडोज़ में। ऐसा लगता है कि आईपीसी :: ओपनएक्स सामान्य फाइलहेडल्स का उपयोग करता है, इसलिए आप इसे बनाए गए हैंडल के साथ select का उपयोग करने में सक्षम नहीं होंगे।

यदि आपको प्रदान की जाने वाली गतिविधि के टाइमआउट/पहचान की आवश्यकता नहीं है, तो आप हैंडल को गैर-अवरुद्ध करने के लिए सेट कर सकते हैं और केवल सामान्य के अनुसार पढ़ या लिख ​​सकते हैं।

यदि आपको अधिक प्रचलित नियंत्रण की आवश्यकता है, तो IPC::Run आपके लिए अच्छा काम कर सकता है।

आप socketpair बनाने और अपने बच्चों की प्रक्रियाओं के साथ उन हैंडल का उपयोग भी देख सकते हैं। नए प्रतिलिपि (5.8 और ऊपर) समर्थन socketpair टीसीपी सॉकेट का उपयोग कर विंडोज पर अनुकरण।

यदि आप कंसोल के बिना चलने वाले प्रोग्राम के लिए STDOUT और STDERR क्लोन करने का प्रयास करते हैं (यानी इसे पर्ल के बजाय, wperl के साथ शुरू किया गया है), तो आप STDIO के माध्यम से डेटा प्राप्त नहीं कर पाएंगे।

प्रैक्टिस में यह कई परियोजनाओं पर मेरे लिए एक बड़ा दर्द रहा है। जो मैंने पाया वह सबसे अच्छा काम करता था बच्चे के प्रक्रिया को टीसीपी के माध्यम से मूल सर्वर से कनेक्ट करने के लिए लिखना था। यदि आप बाल प्रक्रियाओं को नियंत्रित नहीं करते हैं, तो IPC::Run या socketpair देखें।

+1

हाँ, विंडोज बेकार है। वहां चलते समय, आईपीसी :: रन सॉकेट चाल का उल्लेख करता है। – ephemient

+0

जैसा कि मैंने इस सवाल में लिखा था, मैं या तो Fcntl या IO :: हैंडल के माध्यम से हैंडल को गैर-अवरुद्ध करने में असमर्थ था। यदि आपको ऐसा करने का कोई तरीका पता है (जो विंडोज़ पर काम करता है) तो कृपया इसे साझा करें। –

+0

@ माइकल: अवरुद्ध आईओ को एक अलग प्रक्रिया में चलाएं। सॉकेट का उपयोग करके मुख्य प्रक्रिया के साथ आगे और पीछे संचार करें। बाल प्रक्रिया अवरुद्ध हो सकती है, लेकिन मुख्य प्रक्रिया संचार सॉकेट पर गैर-अवरुद्ध I/O कर सकती है। दाओटोड 'सॉकेटपेयर' के साथ सुझाव देता है। – ephemient

0

गैर-अवरुद्ध आईओ विंडोज पर कठिन है। इस मामले में, आप एक नियमित फाइल करने के लिए cleartool के उत्पादन में भेज सकता है, और seek उपयोग करने के लिए फाइल पर हर बार बाहर फ़ाइल से पढ़ने EOF ध्वज रीसेट करने के लिए:

my($cin, $cout); 
my $somefile = "some/file"; 
open($cin, "| cleartool > $somefile"); 
open($cout, '<', $somefile); 

... 

print $cin "$command_for_cleartool\n"; 
# if necessary, wait until cleartool finishes with new output 
seek $cout, 0, 1;  # clear eof condition from previous read 
my @cleartool_output = <$cout>; # capture recent output 
... process output ... 

हालांकि यह शायद कि काम नहीं करेगा ठीक है अगर क्लीयरूल अपने आउटपुट को बफर करता है।

1

एक और क्लज sysread का उपयोग बड़े या असंभव बफर आकार के साथ करना है।

print $cin "$command_for_cleartool\n"; 
    my ($description, $maxlen, $buffer) = ("", 65336); 
    while (my $n = sysread $cout, $buffer, $maxlen) { 
     $description .= $buffer; 
     last if $n < $maxlen; 
    } 
    ... do something with $description ... 

sysread अगर वहाँ वास्तव में कर रहे हैं इनपुट के 0 बाइट्स पढ़ जाने की प्रतीक्षा रखती हूँ। तो उपरोक्त कोड लटका होगा यदि क्लीयरूल 65336 बाइट्स के कुछ बहुमत उत्पन्न करता है। यदि आप प्रोग्राम से आउटपुट के आकार पर एक अच्छा ऊपरी बाउंड जानते हैं, तो आप उस मान का उपयोग $maxlen के ऊपर कर सकते हैं। अन्यथा, आप एक बड़ी और असंभव संख्या चुन सकते हैं और प्रार्थना कर सकते हैं ...

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