यदि आप नहीं जानते हैं, लेकिन सीखना चाहते हैं कि एक प्रोग्राम कैसे बनाया जाए जो लगातार आपकी मेमोरी में लटका रहे और समय-समय पर आपकी ज़रूरत के अनुसार कुछ करता रहे, और साथ ही साथ आप पर्ल में लिखते हैं, तो मैं इसे स्पष्ट रूप से यथासंभव समझाने की कोशिश करता हूं।
मैं स्वयं विस्तृत निर्देशों से प्यार करता हूं, जिसका अर्थ है कि इसे पढ़ने वाले व्यक्ति को वह सब कुछ जानना आवश्यक नहीं है जो याद किया गया था। बेहतर है कि उसे वह याद करने दें जो वह पहले से जानता है। इसके अलावा, वह किसी चीज़ के बारे में गलत विचार रख सकता है।
ठीक है, इसलिए उबाऊ नहीं होना चाहिए, यह उदाहरण एक अन्य विषय के साथ संगत है - इक्का, ताकि हमें इश्क-बॉट मिल जाए।
शुरुआत के लिए, राक्षसों के बारे में।
Win32 के तहत पर्ल के विकास और यहां तक कि कांटा फ़ंक्शन के अनुकरण की संभावना के बावजूद, मैं यूनिक्स के बारे में बात करूंगा। वैसे भी, icq सर्वर के साथ संचार करने के लिए आवश्यक मॉड्यूल win32 के तहत तेज नहीं होता है।
सीधे शब्दों में, यूनिक्स में, प्रत्येक निष्पादन योग्य प्रोग्राम एक विशिष्ट संख्या के साथ एक प्रक्रिया को जन्म देता है। एक कार्यक्रम अन्य कार्यक्रम चला सकता है - इस मामले में, यह माता-पिता बन जाता है, और लॉन्च - बच्चे। यदि पैरेंट प्रोग्राम काम करना बंद कर देता है, तो बच्चे प्रोग्राम भी काम करना बंद कर देते हैं।
उसी समय, आइक-बॉट को लगातार काम करना चाहिए, इसकी परवाह किए बिना कि इसे कहां से लॉन्च किया गया था, और क्या इस प्रक्रिया को शुरू करने वाले एक और कार्यक्रम ने काम करना बंद कर दिया। उदाहरण के लिए, मैंने ssh के माध्यम से सर्वर में लॉग इन किया, bash का उपयोग करने से मैंने एक बॉट लॉन्च किया। मैं बैश और ssh कनेक्शन को बंद करने के बाद, बॉट को काम करना जारी रखना चाहिए, जैसे कि कुछ भी नहीं हुआ था।
कांटा फ़ंक्शन इस उद्देश्य को पूरा करता है, जो एक बच्चे की प्रक्रिया शुरू करता है जो उस टर्मिनल से जुड़ा नहीं है जहां से माता-पिता को लॉन्च किया गया था। अगला, आपको सेटसाइड फ़ंक्शन को कॉल करने की आवश्यकता है, जो हमारी प्रक्रिया के अलगाव को पूरा करता है।
इन कार्यों के बाद, नवजात डेमॉन, यदि वह एक अच्छा दानव बनना चाहता है, तो उसे कार्यशील निर्देशिका को रूट निर्देशिका में बदलने की आवश्यकता है - अगर वह माउंट से जुड़ा हुआ विभाजन से शुरू हुआ था। अन्यथा, विभाजन व्यस्त होगा, और इसे अक्षम करना संभव नहीं होगा।
इसके अलावा, चूंकि डेमॉन द्वारा टर्मिनल से आउटपुट और टर्मिनल से आउटपुट का प्रदर्शन नहीं किया जाएगा, इसलिए इन मानक चैनलों को शून्य पर पुनर्निर्देशित करना आवश्यक है। यदि आप बॉट की निगरानी करना चाहते हैं, तो आप आउटपुट को लॉग फ़ाइल में पुनर्निर्देशित कर सकते हैं।
ट्रिक फंक्शन का उपयोग फोर्क फंक्शन का उपयोग करना है। वह एक और एक ही प्रक्रिया बनाता है। उनके बीच एकमात्र अंतर यह है कि पहला माता-पिता था, और समाप्त होना चाहिए, और दूसरा एक बच्चा है, और रहना चाहिए। इसलिए, प्रक्रिया को आत्म-पहचान की आवश्यकता है - मैं कौन हूं?
यह परिणाम की जाँच करके प्राप्त किया जाता है कि कांटा फ़ंक्शन देता है। यदि यह एक नॉनजेरो वैल्यू लौटाता है, तो यह उस नई चाइल्ड प्रोसेस की पिड है जिसे शुरू किया गया था। इसलिए मैं एक माता-पिता हूं, और मैं जा रहा हूं। यदि पीआईडी शून्य है, तो मैं एक बेटी हूं और मैं काम करना जारी रखता हूं
नतीजतन, इस प्रक्रिया का demonization फ़ंक्शन निम्नानुसार है:
sub Daemonize { <br/>
return if ( $^O eq 'MSWin32' ) ; # , <br/>
chdir '/' or die "Can't chdir to /: $!" ; # unmount <br/>
umask 0 ; # <br/>
open STDIN , '/dev/null' or die "Can't read /dev/null: $!" ; # <br/>
open STDOUT , '>/dev/null' or die "Can't write to /dev/null: $!" ; # <br/>
open STDERR , '>/dev/null' or die "Can't write to /dev/null: $!" ; # <br/>
defined ( my $pid = fork ) or die "Can't fork: $!" ; # fork <br/>
exit if $pid ; # , id <br/>
setsid or die "Can't start a new session: $!" ; # <br/>
} <br/>
संदेश प्रसंस्करण
आईसीक्यू बॉट, सिद्धांत रूप में, कुछ संदेश भेजने और प्राप्त लोगों को संसाधित करना चाहिए। चलो बॉट का एक सरल संस्करण बनाते हैं, जो एक नोटिफ़ायर के रूप में काम करता है - भेजता है जहां इसे सिस्टम से संदेश प्राप्त करना चाहिए, और बस आने वाले संदेशों के लिए एक मानक प्रतिक्रिया देता है। और स्पष्टता के लिए, हम एक कमांड की प्रोसेसिंग करेंगे - छोड़ें।
और फिर यह सब आपकी कल्पना पर निर्भर करता है - आप आने वाले संदेशों को अपनी पसंद के अनुसार संसाधित कर सकते हैं, और यहां आप बहुत सारी दिलचस्प चीजों के साथ आ सकते हैं - सिस्टम विशेषताओं को जारी करने से लेकर कृत्रिम बुद्धिमत्ता तक।
फ़ाइलों से वितरण के लिए संदेश प्राप्त करने का सबसे आसान तरीका। आपको आउटगोइंग संदेशों वाली फ़ाइलों के लिए एक अलग निर्देशिका बनाने की आवश्यकता है। प्रोग्राम जिन्हें संदेश भेजने की आवश्यकता है, उन्हें इस फ़ोल्डर में संग्रहीत किया जाएगा।
बॉट को समय-समय पर इसकी जांच करनी होगी और यदि नए संदेश मिलते हैं, तो उन्हें भेजें।
ऐसा करते हैं - प्रपत्र nnn.rrr की फ़ोल्डर फ़ाइलों में बनाया जाएगा, जहाँ nnn प्राप्तकर्ता का आईकिन UIN है, और rrr यादृच्छिक संख्या है ताकि कई बार एक ही बार में एक नंबर पर गिरने पर फाइलें अधिलेखित न हों।
कुल - हमें इनबॉक्स को स्कैन करने की आवश्यकता है, और प्रत्येक फ़ाइल के लिए फ़ाइल नाम में इंगित संख्या में अपनी सामग्री भेजें।
sub CheckTasks { <br/>
# <br/>
my ( $file , $path , $text , $size , $recipient ) ; <br/>
<br/>
$path = "~username/icq/icq_tasks" ; # <br/>
<br/>
opendir DIR , $path ; <br/>
for $file ( grep /^\d+\.\d+$/ , readdir DIR ) { # nnn.rrr <br/>
$file =~/^ ( \d + ) \ . \d + $/ ; <br/>
$recipient = $1 ; # - UIN <br/>
$size = ( stat ( "$path/$file" ) ) [ 7 ] ; <br/>
if ( $size > 0 && $size < 200 ) { # <br/>
$text = ReadFile ( "$path/$file" ) ; # <br/>
unlink ( "$path/$file" ) ; # <br/>
$oscar -> send_im ( $recipient , $text ) ; # . , oscar - <br/>
} <br/>
} <br/>
} <br/>
मुख्य कार्यक्रम
सहायक कार्य, हमने लगभग सब कुछ किया है। अब मुख्य कार्यक्रम बनाते हैं।
ICQ सर्वर के साथ बातचीत करने के लिए, मैं
नेट :: OSCAR मॉड्यूल का उपयोग करता हूं। यह एक ऑब्जेक्ट मॉड्यूल है, इसलिए हमें एक ऑब्जेक्ट बनाने की आवश्यकता है जो सर्वर से कनेक्ट हो, इसके साथ संवाद करे, और समय-समय पर सर्वर को किक करे ताकि यह हमें डिस्कनेक्ट न करे। इसके अलावा, कनेक्शन की स्थिति की जांच करना और ब्रेक के मामले में, फिर से कनेक्ट करना आवश्यक है। और हां, संदेश भेजें और प्राप्त करें।
आइए जाने:
#!/usr/bin/perl -w <br/>
<br/>
use Net :: OSCAR ; # <br/>
use strict ; # strict <br/>
use POSIX qw ( setsid ) ; # POSIX, <br/>
<br/>
Daemonize ( ) ; # <br/>
<br/>
my ( $UIN , $PASSWORD , $oscar , $t ) ; <br/>
<br/>
$UIN = '123456' ; # UIN <br/>
$PASSWORD = 'mypass' ; # UIN <br/>
<br/>
$oscar = Net :: OSCAR -> new ( ) ; # icq <br/>
$oscar -> set_callback_im_in ( \&send_answer ) ; <br/>
# - <br/>
$t = 0 ; # <br/>
<br/>
while ( 1 ) { # <br/>
if ( ! $oscar -> is_on && ( time ( ) - $t ) > 120 ) { # 2 ! <br/>
$oscar -> signon ( $UIN , $PASSWORD ) ; # <br/>
$t = time ( ) ; # <br/>
} <br/>
$oscar -> do_one_loop ( ) ; # <br/>
CheckTasks ( ) if ( $oscar -> is_on ) ; # - <br/>
sleep ( 5 ) ; # 5 , <br/>
}
मैं कुछ बिंदुओं के बारे में अधिक विस्तार से बताऊंगा:
मॉड्यूल घटनाओं को संभालता है, जिनमें से एक आने वाले संदेश की प्राप्ति है। ताकि बॉट ऐसे संदेशों के जवाब भेज सके, हम इस घटना पर send_answer () फ़ंक्शन के लिए एक कॉल लटकाते हैं:
$ ऑस्कर -> set_callback_im_in (\ & send_answer)
यह इस तरह लग सकता है:
sub send_answer ( ) { <br/>
my ( $oscar , $sender , $msg ) = @_ ; <br/>
# - <br/>
# , <br/>
if ( $msg eq "quit" ) { # . - <br/>
$oscar -> signoff ( ) ; # <br/>
exit ( ) ; # - <br/>
} <br/>
$oscar -> send_im ( $sender , ' , , .' ) ; <br/>
# <br/>
}
sub send_answer ( ) { <br/>
my ( $oscar , $sender , $msg ) = @_ ; <br/>
# - <br/>
# , <br/>
if ( $msg eq "quit" ) { # . - <br/>
$oscar -> signoff ( ) ; # <br/>
exit ( ) ; # - <br/>
} <br/>
$oscar -> send_im ( $sender , ' , , .' ) ; <br/>
# <br/>
}
तो, हम एक इनबाउंड हैंडलर बनाते हैं और एक अंतहीन लूप में आउटबाउंड प्रोसेसिंग को संभालते हैं। यह जांचने के लिए कि क्या हम ऑनलाइन हैं, $ ऑस्कर का उपयोग करें-> is_on ध्वज
और कनेक्शन अनुरोधों के साथ बहुत बार हथौड़ा नहीं करने के लिए, हम एक टाइमर का उपयोग करते हैं - अंतिम कनेक्शन के प्रयास का समय $ t में संग्रहीत किया जाता है। विशेष रूप से, यह खंड प्रोग्राम लॉन्च होने के बाद काम करेगा, सर्वर से पहला कनेक्शन स्थापित करने के लिए।
यदि हम ऑनलाइन हैं, तो हम समय-समय पर $ ऑस्कर-> do_one_loop () पद्धति को कॉल करते हैं, जो हमारे बॉट को लॉग इन रखता है।
और अगर हम नेटवर्क पर हैं, तो हम आने वाले संदेशों के फ़ोल्डर की जांच करते हैं, और यदि आवश्यक हो तो उन्हें भेजें।
हम रचना करते हैं, बचाते हैं, चलाते हैं। सरलतम इक बॉट तैयार है! मैं सर्वर से मुझे सूचनाएं भेजने के लिए ऐसे बॉट का उपयोग करता हूं।
अब क्या?
इस बॉट की कमियों के बीच, मैं ध्यान देता हूं कि नेट :: OSCAR मॉड्यूल ऑफ़लाइन उपयोगकर्ताओं को संदेश भेजने में सक्षम नहीं है।
होमवर्क के रूप में, मैं निम्नलिखित प्रस्ताव करता हूं:
- चौथे पर - पहले लॉन्च के तुरंत बाद बॉट को आईसीक्यू से कनेक्ट करने के लिए, बजाय 2 मिनट प्रतीक्षा करें
- प्लस के साथ चार पर - ReadFile फ़ंक्शन लिखें
- पांच के लिए - नेट :: OSCAR प्रलेखन को समझें, बॉट को यह निर्धारित करने के लिए सिखाएं कि क्या संदेश प्राप्तकर्ता ऑफ़लाइन है और उसे ऑफ़लाइन संदेश न भेजें।