JavaRush /جاوا بلاگ /Random-UR /ساکٹ اور سرور ساکٹ کلاسز، یا "ہیلو، سرور؟ کیا تم مجھے سن ...
Sergey Simonov
سطح
Санкт-Петербург

ساکٹ اور سرور ساکٹ کلاسز، یا "ہیلو، سرور؟ کیا تم مجھے سن سکتے ہو؟"

گروپ میں شائع ہوا۔
تعارف: "میز پر ایک کمپیوٹر تھا، اس کے پیچھے ایک انکوڈر تھا..." ساکٹ اور سرور ساکٹ کلاسز، یا "ہیلو، سرور؟  کیا تم مجھے سن سکتے ہو؟"  - 1 ایک دفعہ کا ذکر ہے، میرے ایک ہم جماعت نے اپنے جاوا کے مطالعہ کا ایک اور نتیجہ ایک نئے پروگرام کے اسکرین شاٹ کی صورت میں پوسٹ کیا۔ یہ پروگرام ایک ملٹی یوزر چیٹ تھا۔ اس وقت میں اس زبان میں پروگرامنگ میں مہارت حاصل کرنے میں اپنا سفر شروع کر رہا تھا، لیکن میں نے یقینی طور پر اپنے آپ کو نوٹ کیا کہ "میں یہ چاہتا ہوں!" وقت گزرتا گیا اور، اپنے پروگرامنگ کے علم کو گہرا کرنے کے ایک حصے کے طور پر اگلے پروجیکٹ پر کام کرنے کے بعد، مجھے وہ واقعہ یاد آیا اور فیصلہ کیا کہ اب وقت آگیا ہے۔ کسی نہ کسی طرح میں نے تجسس کی وجہ سے پہلے ہی اس موضوع کو کھودنا شروع کر دیا تھا، لیکن جاوا کی میری بنیادی نصابی کتاب میں (یہ Schildt کا مکمل دستی تھا) java.net پیکج کے لیے صرف 20 صفحات فراہم کیے گئے تھے۔ یہ قابل فہم ہے - کتاب پہلے ہی بہت بڑی ہے۔ مین کلاسز کے طریقوں اور کنسٹرکٹرز کی میزیں تھیں، لیکن بس۔ اگلا مرحلہ، یقیناً، اللہ تعالیٰ گوگل ہے: متعدد مضامین کے ہزاروں جہاں ایک ہی چیز پیش کی گئی ہے - ساکٹ کے بارے میں دو یا تین الفاظ، اور ایک ریڈی میڈ مثال۔ کلاسک نقطہ نظر (کم از کم میرے مطالعہ کے انداز میں) سب سے پہلے یہ سمجھنا ہے کہ مجھے کام کے آلات سے کیا ضرورت ہے، وہ کیا ہیں، ان کی ضرورت کیوں ہے، اور صرف اس صورت میں، اگر مسئلہ کا حل واضح نہیں ہے، تو منتخب کریں۔ ریڈی میڈ لسٹنگ، گری دار میوے اور بولٹ کو کھولنا. لیکن میں نے سوچا کہ کیا ہے اور آخر کار ایک کثیر صارف چیٹ لکھی۔ ظاہری طور پر، یہ کچھ اس طرح نکلا: ساکٹ اور سرور ساکٹ کلاسز، یا "ہیلو، سرور؟  کیا تم مجھے سن سکتے ہو؟"  - 2یہاں میں آپ کو چیٹ ڈیزائن کی مثال کا استعمال کرتے ہوئے جاوا ساکٹ پر مبنی کلائنٹ سرور ایپلی کیشنز کی بنیادی باتوں کو سمجھنے کی کوشش کروں گا۔ جاوارش کورس میں آپ چیٹ کریں گے۔ یہ بالکل مختلف سطح پر ہو گا، خوبصورت، بڑا، ملٹی فنکشنل۔ لیکن سب سے پہلے، آپ کو ہمیشہ بنیاد ڈالنے کی ضرورت ہے، لہذا یہاں ہمیں یہ معلوم کرنے کی ضرورت ہے کہ اس طرح کے حصے کی بنیاد کیا ہے۔ (اگر آپ کو کوئی کوتاہیاں یا خامیاں نظر آئیں تو پی ایم میں یا آرٹیکل کے نیچے کمنٹ میں لکھیں)۔ چلو شروع کریں. ہیڈ ون: "وہ گھر جو..." یہ بتانے کے لیے کہ ایک سرور اور ایک کلائنٹ کے درمیان نیٹ ورک کنکشن کیسے ہوتا ہے، آئیے اب ایک اپارٹمنٹ کی عمارت کی بہترین مثال لیں۔ ہم کہتے ہیں کہ ایک کلائنٹ کو کسی نہ کسی طرح کسی مخصوص سرور کے ساتھ کنکشن قائم کرنے کی ضرورت ہے۔ تلاش کرنے والے کو سرچ آبجیکٹ کے بارے میں کیا جاننے کی ضرورت ہے؟ ہاں، ایڈریس۔ سرور بادل پر کوئی جادوئی ہستی نہیں ہے، اور اس لیے اسے ایک مخصوص مشین پر واقع ہونا چاہیے۔ ایک گھر کے ساتھ مشابہت کے ساتھ، جہاں دو فریقوں کی متفقہ میٹنگ ہونی چاہیے۔ اور اپارٹمنٹ کی عمارت میں ایک دوسرے کو تلاش کرنے کے لیے، عمارت کا ایک پتہ کافی نہیں ہے؛ آپ کو اپارٹمنٹ کا نمبر بتانا ہوگا جس میں میٹنگ ہوگی۔ اسی طرح، ایک کمپیوٹر پر ایک ساتھ کئی سرور ہو سکتے ہیں، اور کلائنٹ کو کسی مخصوص سے رابطہ کرنے کے لیے، اسے وہ پورٹ نمبر بھی بتانا ہوگا جس کے ذریعے کنکشن ہوگا۔ تو، پتہ اور پورٹ نمبر۔ ایڈریس کا مطلب ہے انٹرنیٹ اسپیس میں مشین کا شناخت کنندہ۔ یہ ایک ڈومین نام ہو سکتا ہے، مثال کے طور پر، "javarush.ru" یا ایک باقاعدہ IP۔ بندرگاہ- ایک منفرد نمبر جس کے ساتھ ایک مخصوص ساکٹ منسلک ہے (اس اصطلاح پر بعد میں بات کی جائے گی)، دوسرے لفظوں میں، اس پر کسی خاص سروس کا قبضہ ہے تاکہ اسے اس سے رابطہ کرنے کے لیے استعمال کیا جا سکے۔ لہذا ایک (سرور) کی سرزمین پر کم از کم دو اشیاء کے ملنے کے لیے، علاقے کے مالک (سرور) کو اس (کار) پر ایک مخصوص اپارٹمنٹ (بندرگاہ) پر قبضہ کرنا چاہیے، اور دوسرے کو یہ جانتے ہوئے کہ ملاقات کی جگہ تلاش کرنی چاہیے۔ گھر کا پتہ (ڈومین یا آئی پی)، اور اپارٹمنٹ نمبر (پورٹ)۔ ہیڈ ٹو: میٹ ساکٹ نیٹ ورک پر کام کرنے سے متعلق تصورات اور اصطلاحات میں سے ایک بہت اہم ساکٹ ہے۔ یہ اس نقطہ کی نشاندہی کرتا ہے جس کے ذریعے کنکشن ہوتا ہے۔ سیدھے الفاظ میں، ایک ساکٹ نیٹ ورک پر دو پروگراموں کو جوڑتا ہے۔ کلاس Socketساکٹ کے خیال کو نافذ کرتی ہے۔ کلائنٹ اور سرور اپنے ان پٹ/آؤٹ پٹ چینلز کے ذریعے بات چیت کریں گے: ساکٹ اور سرور ساکٹ کلاسز، یا "ہیلو، سرور؟  کیا تم مجھے سن سکتے ہو؟"  - 3 اس کلاس کا اعلان کلائنٹ کی طرف کیا جاتا ہے، اور سرور اسے دوبارہ بناتا ہے، کنکشن سگنل موصول ہوتا ہے۔ اس طرح آن لائن مواصلات کام کرتا ہے۔ شروع کرنے کے لیے، یہاں ممکنہ کلاس کنسٹرکٹر ہیں Socket:
Socket(String Name_хоста, int порт) throws UnknownHostException, IOException
Socket(InetAddress IP-address, int порт) throws UnknownHostException
"host_name" - ایک مخصوص نیٹ ورک نوڈ، IP ایڈریس کا مطلب ہے۔ اگر ساکٹ کلاس اسے اصلی، موجودہ ایڈریس میں تبدیل نہیں کر سکتی ہے، تو پھر ایک استثناء دیا جائے گا UnknownHostException۔ بندرگاہ ایک بندرگاہ ہے۔ اگر 0 کو پورٹ نمبر کے طور پر بیان کیا گیا ہے، تو سسٹم خود ایک مفت پورٹ مختص کرے گا۔ اگر کنکشن منقطع ہو جائے تو ایک استثناء بھی ہو سکتا ہے IOException۔ واضح رہے کہ دوسرے کنسٹرکٹر میں ایڈریس کی قسم ہے InetAddress۔ یہ بچاؤ کے لیے آتا ہے، مثال کے طور پر، جب آپ کو ایڈریس کے طور پر ڈومین کا نام بتانے کی ضرورت ہوتی ہے۔ اس کے علاوہ، جب ایک ڈومین کا مطلب کئی IP پتے ہوتے ہیں، تو InetAddressآپ ان کی ایک صف حاصل کرنے کے لیے ان کا استعمال کر سکتے ہیں۔ تاہم، یہ آئی پی کے ساتھ بھی کام کرتا ہے۔ آپ میزبان کا نام، بائٹ سرنی بھی حاصل کر سکتے ہیں جو IP ایڈریس بناتا ہے، وغیرہ۔ ہم اس پر تھوڑا آگے جائیں گے، لیکن آپ کو مکمل تفصیلات کے لیے سرکاری دستاویزات پر جانا پڑے گا۔ جب کسی چیز کی قسم شروع کی جاتی ہے Socket، تو کلائنٹ جس سے اس کا تعلق ہے نیٹ ورک پر اعلان کرتا ہے کہ وہ سرور سے ایک مخصوص ایڈریس اور پورٹ نمبر پر جڑنا چاہتا ہے۔ ذیل میں کلاس کے سب سے زیادہ استعمال ہونے والے طریقے ہیں Socket: InetAddress getInetAddress()- ساکٹ کے بارے میں ڈیٹا پر مشتمل آبجیکٹ واپس کرتا ہے۔ اگر ساکٹ منسلک نہیں ہے - null int getPort()- وہ پورٹ واپس کرتا ہے جس پر سرور سے کنکشن ہوتا ہے int getLocalPort()- وہ پورٹ لوٹاتا ہے جس سے ساکٹ پابند ہے۔ حقیقت یہ ہے کہ کلائنٹ اور سرور ایک بندرگاہ پر "مواصلات" کر سکتے ہیں، لیکن وہ بندرگاہیں جن سے وہ جڑے ہوئے ہیں مکمل طور پر مختلف ہو سکتے ہیں boolean isConnected()- اگر کنکشن قائم ہو جائے تو یہ درست ہو جاتا ہے - void connect(SocketAddress address)ایک نئے کنکشن کی نشاندہی کرتا ہے boolean isClosed()- درست واپس آتا ہے، اگر ساکٹ بند ہو boolean isBound()- سچی واپسی، اگر ساکٹ دراصل کسی ایڈریس کا پابند ہے، تو کلاس Socketانٹرفیس کو لاگو کرتی ہے AutoCloseable، لہذا اسے میں استعمال کیا جا سکتا ہے try-with-resources۔ تاہم، آپ close() کا استعمال کرتے ہوئے کلاسک طریقے سے ساکٹ کو بھی بند کر سکتے ہیں۔ ہیڈ تھری: اور یہ ایک سرور ساکٹ ہے ہم کہتے ہیں کہ ہم نے کلاس کی شکل میں Socketکلائنٹ کی طرف سے کنکشن کی درخواست کا اعلان کیا۔ سرور ہماری خواہش کا اندازہ کیسے لگائے گا؟ اس کے لیے سرور کی ایک کلاس ہے جیسے ServerSocket, اور اس میں accept() طریقہ ہے۔ اس کے کنسٹرکٹرز ذیل میں پیش کیے گئے ہیں:
ServerSocket() throws IOException
ServerSocket(int порт) throws IOException
ServerSocket(int порт, int максимум_подключений) throws IOException
ServerSocket(int порт, int максимум_подключений, InetAddress локальный_address) throws IOException
اعلان کرتے وقت، ServerSocket آپ کو کنکشن کا پتہ بتانے کی ضرورت نہیں ہے، کیونکہ مواصلات سرور مشین پر ہوتی ہے۔ صرف ایک ملٹی چینل ہوسٹ کے ساتھ آپ کو یہ بتانے کی ضرورت ہے کہ سرور ساکٹ کس IP کا پابند ہے۔ ہیڈ تھری۔ ون: سرور جو کہتا ہے نہیں چونکہ کسی پروگرام کو اس کی ضرورت سے زیادہ وسائل فراہم کرنا مہنگا اور غیر معقول ہے، اس لیے کنسٹرکٹر میں ServerSocketآپ سے کہا جاتا ہے کہ آپریشن کے دوران سرور کے ذریعہ قبول کردہ زیادہ سے زیادہ کنکشنز کا اعلان کریں۔ اگر اس کی وضاحت نہیں کی گئی ہے، تو پہلے سے طے شدہ طور پر اس نمبر کو 50 کے برابر سمجھا جائے گا۔ جی ہاں، تھیوری میں ہم فرض کر سکتے ہیں کہ ServerSocketیہ وہی ساکٹ ہے، صرف سرور کے لیے۔ لیکن یہ کلاس سے بالکل مختلف کردار ادا کرتا ہے Socket۔ اس کی ضرورت صرف کنکشن بنانے کے مرحلے پر ہے۔ ٹائپ آبجیکٹ بنانے کے بعد، ServerSocketآپ کو یہ معلوم کرنا ہوگا کہ کوئی سرور سے جڑنا چاہتا ہے۔ قبول () طریقہ یہاں منسلک ہے۔ ہدف اس وقت تک انتظار کرتا ہے جب تک کہ کوئی اس سے جڑنا نہیں چاہتا، اور جب ایسا ہوتا ہے تو یہ قسم کی ایک چیز واپس کرتا ہے Socket، یعنی دوبارہ تخلیق کردہ کلائنٹ ساکٹ۔ اور اب چونکہ سرور کی طرف کلائنٹ ساکٹ بنا دیا گیا ہے، دو طرفہ مواصلات شروع ہو سکتے ہیں۔ Socketکلائنٹ سائیڈ پر ٹائپ آبجیکٹ بنانا اور ServerSocketسرور سائیڈ کا استعمال کرتے ہوئے اسے دوبارہ بنانا کنکشن کے لیے کم از کم درکار ہے۔ ہیڈ فور: سانتا کلاز کو خط Вопрос: کلائنٹ اور سرور کس طرح بات چیت کرتے ہیں؟ Ответ:I/O اسٹریمز کے ذریعے۔ ہمارے پاس پہلے سے ہی کیا ہے؟ سرور ایڈریس اور کلائنٹ کے پورٹ نمبر کے ساتھ ایک ساکٹ، اور وہی چیز، سرور کی طرف سے قبول کرنے کا شکریہ۔ لہذا یہ سمجھنا مناسب ہے کہ وہ ساکٹ کے ذریعے بات چیت کریں گے۔ ایسا کرنے کے لیے، دو طریقے ہیں جو اسٹریمز InputStreamاور OutputStreamقسم کی اشیاء تک رسائی فراہم کرتے ہیں Socket۔ وہ یہاں ہیں:
InputStream getInputStream()
OutputStream getOutputStream()
چونکہ ننگے بائٹس کو پڑھنا اور لکھنا اتنا موثر نہیں ہے، اس لیے اسٹریمز کو اڈاپٹر کلاسز میں لپیٹ کر بفر کیا جا سکتا ہے یا نہیں۔ مثال کے طور پر:
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
مواصلات کے دو طرفہ ہونے کے لیے، اس طرح کے آپریشنز کو دونوں طرف سے انجام دیا جانا چاہیے۔ اب آپ اندر استعمال کرکے کچھ بھیج سکتے ہیں، اور باہر استعمال کرکے کچھ وصول کرسکتے ہیں، اور اس کے برعکس۔ دراصل، یہ کلاس کا عملی طور پر واحد کام ہے Socket۔ اور ہاں، flush() طریقہ کے بارے میں مت بھولنا BufferedWriter- یہ بفر کے مواد کو فلش کرتا ہے۔ اگر ایسا نہیں کیا جاتا ہے، تو معلومات کو منتقل نہیں کیا جائے گا اور اس لیے موصول نہیں کیا جائے گا۔ موصول ہونے والا تھریڈ لائن آف لائن کے اختتامی اشارے کا بھی انتظار کرتا ہے - "\n"، بصورت دیگر پیغام کو قبول نہیں کیا جائے گا، کیونکہ حقیقت میں پیغام مکمل نہیں ہوا ہے اور مکمل نہیں ہے۔ اگر یہ آپ کے لیے تکلیف دہ معلوم ہوتا ہے، تو پریشان نہ ہوں، آپ ہمیشہ کلاس استعمال کر سکتے ہیں PrintWriter، جس کو ختم کرنے کی ضرورت ہے، دوسری دلیل کے طور پر سچ کی وضاحت کریں، اور پھر بفر سے پاپنگ خود بخود ہو جائے گا:
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
اس کے علاوہ، لائن کے اختتام کی نشاندہی کرنے کی ضرورت نہیں ہے؛ یہ کلاس آپ کے لیے کرتی ہے۔ لیکن کیا سٹرنگ I/O اس کی حد ہے جو ساکٹ کر سکتا ہے؟ نہیں، کیا آپ اشیاء کو ساکٹ اسٹریمز کے ذریعے بھیجنا چاہتے ہیں؟ خدا کا واسطہ. انہیں سیریلائز کریں اور آپ جانے کے لئے تیار ہیں:
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
ہیڈ فائیو: انٹرنیٹ کے ذریعے حقیقی مواصلات چونکہ ایک حقیقی IP ایڈریس کے ساتھ ایک حقیقی نیٹ ورک کے ذریعے جڑنے کے لیے آپ کے پاس ایک مکمل سرور ہونا ضروری ہے، اور چونکہ:
  1. ہماری مستقبل کی چیٹ، ایک افادیت کے طور پر، ایسی صلاحیتیں نہیں رکھتی ہیں۔ یہ صرف ایک کنکشن قائم کر سکتا ہے اور پیغام وصول/بھیج سکتا ہے۔ یعنی اس میں حقیقی سرور کی صلاحیتیں نہیں ہیں۔
  2. ہمارا سرور، جس میں صرف ساکٹ ڈیٹا اور I/O اسٹریمز شامل ہیں، ایک حقیقی WEB یا FTP سرور کے طور پر کام نہیں کر سکتا، پھر صرف اس کے ساتھ ہم انٹرنیٹ پر رابطہ نہیں کر سکیں گے۔
اور اس کے علاوہ، ہم ابھی پروگرام تیار کرنا شروع کر رہے ہیں، جس کا مطلب ہے کہ یہ اتنا مستحکم نہیں ہے کہ فوری طور پر کسی حقیقی نیٹ ورک کے ساتھ کام کر سکے، اس لیے ہم مقامی میزبان کو کنکشن ایڈریس کے طور پر استعمال کریں گے۔ یعنی تھیوری میں، کلائنٹ اور سرور اب بھی کسی بھی طرح سے جڑے نہیں ہوں گے سوائے ساکٹ کے، لیکن پروگرام کو ڈیبگ کرنے کے لیے وہ ایک ہی مشین پر ہوں گے، نیٹ ورک پر حقیقی رابطے کے بغیر۔ کنسٹرکٹر میں یہ بتانے کے لیے Socketکہ پتہ مقامی ہے، 2 طریقے ہیں:
  1. "لوکل ہوسٹ" کو ایڈریس کی دلیل کے طور پر لکھیں، جس کا مطلب مقامی اسٹب ہے۔ "127.0.0.1" بھی اس کے لیے موزوں ہے - یہ صرف ایک سٹب کی ڈیجیٹل شکل ہے۔
  2. InetAddress کا استعمال:
    1. InetAddress.getByName(null)- لوکل ہوسٹ کی طرف null پوائنٹس
    2. InetAddress.getByName("localhost")
    3. InetAddress.getByName("127.0.0.1")
سادگی کے لیے، ہم String قسم کا "localhost" استعمال کریں گے۔ لیکن دیگر تمام اختیارات بھی قابل عمل ہیں۔ ہیڈ سکس: یہ بات چیت کا وقت ہے لہذا، ہمارے پاس پہلے سے ہی وہ سب کچھ موجود ہے جس کی ہمیں سرور کے ساتھ گفتگو کے سیشن کو نافذ کرنے کی ضرورت ہے۔ جو کچھ باقی ہے اسے ایک ساتھ رکھنا ہے: درج ذیل فہرست سے پتہ چلتا ہے کہ کلائنٹ کس طرح سرور سے جڑتا ہے، اسے ایک پیغام بھیجتا ہے، اور سرور، بدلے میں، اس بات کی تصدیق کرتا ہے کہ اس نے پیغام موصول کیا ہے اسے اس میں دلیل کے طور پر استعمال کرتے ہوئے: "سرور۔ جاوا"
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {

    private static Socket clientSocket; // socket for communication
    private static ServerSocket server; // server socket
    private static BufferedReader in; // socket read stream
    private static BufferedWriter out; // socket write stream

    public static void main(String[] args) {
        try {
            try  {
                server = new ServerSocket(4004); // server socket listening on port 4004
                System.out.println("Server is running!"); // server would be nice
                // announce your launch
                clientSocket = server.accept(); // accept() will wait until
                //someone won't want to connect
                try { // after establishing a connection and recreating the socket for communication with the client, you can go
                    // to create I/O streams.
                    // now we can receive messages
                    in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                    // and send
                    out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));

                    String word = in.readLine(); // wait for the client to write something to us
                    System.out.println(word);
                    // without hesitation responds to the client
                    out.write("Hi, this is the Server! I confirm you wrote: " + word + "\n");
                    out.flush(); // push everything out of the buffer

                } finally { // in any case, the socket will be closed
                    clientSocket.close();
                    // streams would also be nice to close
                    in.close();
                    out.close();
                }
            } finally {
                System.out.println("Server closed!");
                    server.close();
            }
        } catch (IOException e) {
            System.err.println(e);
        }
    }
"کلائنٹ۔جاوا"
import java.io.*;
import java.net.Socket;

public class Client {

    private static Socket clientSocket; // socket for communication
    private static BufferedReader reader; // we need a reader that reads from the console, otherwise
    // do we know what the client wants to say?
    private static BufferedReader in; // socket read stream
    private static BufferedWriter out; // socket write stream

    public static void main(String[] args) {
        try {
            try {
                // address - local host, port - 4004, same as the server
                clientSocket = new Socket("localhost", 4004); // with this line we request
                // the server has access to the connection
                reader = new BufferedReader(new InputStreamReader(System.in));
                // read messages from the server
                in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                // write there
                out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));

                System.out.println("Did you have something to say? Enter it here:");
                // if the connection happened and the threads were successfully created - we can
                // work further and offer the client something to enter
                // if not, an exception will be thrown
                String word = reader.readLine(); // wait for the client to do something
                // will not write to the console
                out.write(word + "\n"); // send a message to the server
                out.flush();
                String serverWord = in.readLine(); // wait for the server to say
                System.out.println(serverWord); // received - display
            } finally { // in any case, you need to close the socket and streams
                System.out.println("The client has been closed...");
                clientSocket.close();
                in.close();
                out.close();
            }
        } catch (IOException e) {
            System.err.println(e);
        }

    }
}
یقینا، آپ کو پہلے سرور کو شروع کرنا چاہئے، کیونکہ اگر کوئی ایسی چیز نہیں ہے جو اسے مربوط کرے گی تو کلائنٹ اسٹارٹ اپ پر کس چیز سے جڑے گا؟ :) آؤٹ پٹ اس طرح ہوگا: /* کیا آپ کچھ کہنا چاہتے ہیں؟ اسے یہاں درج کریں: ہیلو، سرور؟ کیا تم مجھے سن سکتے ہو؟ ہیلو، یہ سرور ہے! میں تصدیق کرتا ہوں، آپ نے لکھا: ہیلو، سرور؟ کیا تم مجھے سن سکتے ہو؟ کلائنٹ بند کر دیا گیا تھا... */ Hurray! ہم نے سرور کو کلائنٹ کے ساتھ بات چیت کرنا سکھایا! تاکہ بات چیت دو نقلوں میں نہیں ہوتی، بلکہ جتنی آپ چاہیں، صرف دھاگوں کے پڑھنے اور لکھنے کو تھوڑی دیر (سچ) لوپ میں لپیٹیں اور باہر نکلنے کے لیے اشارہ کریں جو کہ ایک مخصوص پیغام کے مطابق، مثال کے طور پر، "ایگزٹ" ، سائیکل میں خلل پڑا، اور پروگرام ختم ہو جائے گا۔ ہیڈ سیون: ملٹی یوزر بہتر ہے۔ حقیقت یہ ہے کہ سرور ہمیں سن سکتا ہے، لیکن یہ بہت بہتر ہو گا اگر ہم اپنی نوعیت کے کسی سے بات کر سکیں۔ میں مضمون کے آخر میں تمام ذرائع منسلک کروں گا، اس لیے یہاں میں ہمیشہ بڑے نہیں، لیکن کوڈ کے اہم ٹکڑے دکھاؤں گا جو کہ اگر صحیح طریقے سے استعمال کیا جائے تو، کثیر صارفی چیٹ کو تیار کرنا ممکن بنائے گا۔ لہذا، ہم سرور کے ذریعے کسی دوسرے کلائنٹ کے ساتھ بات چیت کرنے کے قابل ہونا چاہتے ہیں۔ یہ کیسے کرنا ہے؟ ظاہر ہے، چونکہ کلائنٹ پروگرام کا اپنا طریقہ ہے main، اس کا مطلب ہے کہ اسے سرور سے الگ اور دوسرے کلائنٹس کے ساتھ متوازی طور پر لانچ کیا جا سکتا ہے۔ یہ ہمیں کیا دیتا ہے؟ کسی نہ کسی طرح، یہ ضروری ہے کہ ہر نئے کنکشن کے ساتھ سرور فوری طور پر مواصلات میں نہ جائے، لیکن اس کنکشن کو کسی قسم کی فہرست میں لکھے اور نئے کنکشن کا انتظار کرنے کے لیے آگے بڑھے، اور کسی قسم کی معاون سروس کسی مخصوص کے ساتھ رابطے میں مصروف ہے۔ کلائنٹ اور کلائنٹس کو سرور کو لکھنا چاہیے اور ایک دوسرے سے آزادانہ طور پر جواب کا انتظار کرنا چاہیے۔ دھاگے بچاؤ کے لیے آتے ہیں۔ ہم کہتے ہیں کہ ہمارے پاس ایک کلاس ہے جو نئے کنکشن کو یاد رکھنے کے لیے ذمہ دار ہے: اس میں درج ذیل کی وضاحت ہونی چاہیے:
  1. پورٹ نمبر۔
  2. وہ فہرست جس میں یہ نیا کنکشن لکھتا ہے۔
  3. اور ServerSocket، ایک ہی (!) کاپی میں۔
public class Server {

    public static final int PORT = 8080;
    public static LinkedList<ServerSomthing> serverList = new LinkedList<>(); // list of all threads

    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(PORT);
            try {
            while (true) {
                // Blocks until a new connection is made:
                Socket socket = server.accept();
                try {
                    serverList.add(new ServerSomthing(socket)); // add a new connection to the list
                } catch (IOException e) {
                    // If it fails, the socket is closed,
                    // otherwise, the thread will close it when it exits:
                    socket.close();
                }
            }
        } finally {
            server.close();
        }
    }
}
ٹھیک ہے، اب ہر دوبارہ تخلیق شدہ ساکٹ ضائع نہیں ہوگا، بلکہ سرور پر محفوظ کیا جائے گا۔ مزید. ہر گاہک کو کسی کو سننے کی ضرورت ہوتی ہے۔ آئیے آخری باب سے سرور کے افعال کے ساتھ ایک تھریڈ بناتے ہیں۔
class ServerSomthing extends Thread {

    private Socket socket; // socket through which the server communicates with the client,
    // except for it - the client and server are not connected in any way
    private BufferedReader in; // socket read stream
    private BufferedWriter out; // socket write stream

    public ServerSomthing(Socket socket) throws IOException {
        this.socket = socket;
        // если потоку ввода/вывода приведут к генерированию исключения, оно пробросится дальше
        in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        start(); // call run()
    }
    @Override
    public void run() {
        String word;
        try {

            while (true) {
                word = in.readLine();
                if(word.equals("stop")) {
                    break;                }
                for (ServerSomthing vr : Server.serverList) {
                    vr.send(word); // send the received message with
                   // bound client to everyone else including him
                }
            }

        } catch (IOException e) {
        }
    }

    private void send(String msg) {
        try {
            out.write(msg + "\n");
            out.flush();
        } catch (IOException ignored) {}
    }
}
لہذا، سرور تھریڈ کے کنسٹرکٹر میں، ایک ساکٹ شروع کرنا ضروری ہے جس کے ذریعے تھریڈ ایک مخصوص کلائنٹ کے ساتھ بات چیت کرے گا۔ نیز I/O تھریڈز، اور ہر وہ چیز جس کی آپ کو براہ راست کنسٹرکٹر سے تھریڈ شروع کرنے کی ضرورت ہے۔ ٹھیک ہے، لیکن کیا ہوتا ہے جب سرور تھریڈ کلائنٹ کا پیغام پڑھتا ہے؟ صرف اپنے کلائنٹ کو واپس بھیجیں؟ بہت موثر نہیں۔ ہم ایک ملٹی یوزر چیٹ بنا رہے ہیں، اس لیے ہمیں ہر ایک منسلک کلائنٹ کی ضرورت ہے جو ایک شخص نے لکھا ہے۔ آپ کو ان کے کلائنٹس سے وابستہ تمام سرور تھریڈز کی فہرست استعمال کرنے کی ضرورت ہے اور بھیجے گئے ہر پیغام کو ایک مخصوص تھریڈ پر بھیجنا ہوگا تاکہ وہ اسے اپنے کلائنٹ کو بھیجے:
for (ServerSomthing vr : Server.serverList) {
    vr.send(word); // send the received message
    // from the linked client to everyone else, including him
}
private void send(String msg) {
    try {
        out.write(msg + "\n");
        out.flush();
    } catch (IOException ignored) {}
}
اب تمام کلائنٹس کو معلوم ہو جائے گا کہ ان میں سے ایک نے کیا کہا! اگر آپ نہیں چاہتے ہیں کہ پیغام اس شخص کو بھیجا جائے جس نے اسے بھیجا ہے (وہ پہلے سے ہی جانتا ہے کہ اس نے کیا لکھا ہے!)، صرف دھاگوں کے ذریعے تکرار کرتے وقت، واضح کریں کہ کسی چیز پر کارروائی کرتے وقت، thisلوپ بغیر کارکردگی کے اگلے عنصر پر چلا جائے گا۔ اس پر کوئی کارروائی۔ یا، اگر آپ چاہیں تو، کلائنٹ کو پیغام بھیجیں کہ پیغام کامیابی سے موصول اور بھیجا گیا ہے۔ سرور کے ساتھ اب سب کچھ واضح ہے۔ آئیے کلائنٹ کی طرف چلتے ہیں، یا بجائے کلائنٹس کی طرف! وہاں سب کچھ یکساں ہے، آخری باب سے کلائنٹ کے ساتھ مشابہت کے ذریعے، صرف اس وقت جب آپ کو ضرورت کی مثال بناتے ہوئے، جیسا کہ سرور کے ساتھ اس باب میں دکھایا گیا ہے، کنسٹرکٹر میں ضروری ہر چیز تخلیق کرنے کے لیے۔ لیکن اگر، ایک کلائنٹ بناتے وقت، اس کے پاس ابھی تک کچھ داخل کرنے کا وقت نہیں ہے، لیکن اسے پہلے ہی کچھ بھیجا گیا ہے؟ (مثال کے طور پر، ان لوگوں کی خط و کتابت کی تاریخ جو اس سے پہلے چیٹ سے جڑ چکے ہیں)۔ لہذا جن چکروں میں بھیجے گئے پیغامات پر کارروائی کی جائے گی ان کو ان سے الگ کیا جانا چاہیے جن میں پیغامات کنسول سے پڑھے جاتے ہیں اور دوسروں کو فارورڈ کرنے کے لیے سرور کو بھیجے جاتے ہیں۔ دھاگے دوبارہ بچاؤ کے لیے آتے ہیں۔ کلائنٹ کو تھریڈ کے طور پر بنانے کا کوئی فائدہ نہیں ہے۔ رن میتھڈ میں لوپ کے ساتھ تھریڈ بنانا زیادہ آسان ہے جو میسجز کو پڑھتا ہے، اور یہ بھی کہ تشبیہ سے لکھتا ہے:
// thread reading messages from the server
private class ReadMsg extends Thread {
    @Override
    public void run() {

        String str;
        try {
            while (true) {
                str = in.readLine(); // waiting for a message from the server
                if (str.equals("stop")) {

                    break; // exit the loop if it's "stop"
                }
                            }
        } catch (IOException e) {

        }
    }
}
// thread sending messages coming from the console to the server
public class WriteMsg extends Thread {

    @Override
    public void run() {
        while (true) {
            String userWord;
            try {
               userWord = inputUser.readLine(); // messages from the console
                if (userWord.equals("stop")) {
                    out.write("stop" + "\n");
                    break; // exit the loop if it's "stop"
                } else {
                    out.write(userWord + "\n"); // send to the server
                }
                out.flush(); // clean up
            } catch (IOException e) {

            }

        }
    }
}
کلائنٹ کنسٹرکٹر میں آپ کو صرف ان تھریڈز کو شروع کرنے کی ضرورت ہے۔ اگر کلائنٹ چھوڑنا چاہتا ہے تو اس کے وسائل کو کیسے بند کیا جائے؟ کیا مجھے سرور تھریڈ کے وسائل کو بند کرنے کی ضرورت ہے؟ ایسا کرنے کے لیے، آپ کو زیادہ تر ممکنہ طور پر ایک الگ طریقہ بنانے کی ضرورت ہوگی جسے میسج لوپ سے باہر نکلتے وقت کہا جاتا ہے۔ وہاں آپ کو ساکٹ اور I/O اسٹریمز کو بند کرنے کی ضرورت ہوگی۔ کسی مخصوص کلائنٹ کے لیے وہی سیشن اینڈ سگنل اس کے سرور تھریڈ پر بھیجا جانا چاہیے، جو اس کے ساکٹ کے ساتھ ایسا ہی کرے اور خود کو مین سرور کلاس میں تھریڈز کی فہرست سے ہٹا دے۔ ہیڈ آٹھ: کمال کی کوئی حد نہیں ہے آپ اپنے پروجیکٹ کو بہتر بنانے کے لیے لامتناہی نئی خصوصیات ایجاد کر سکتے ہیں۔ لیکن بالکل نئے منسلک کلائنٹ کو کیا منتقل کیا جانا چاہئے؟ میرے خیال میں آخری دس واقعات ان کی آمد سے پہلے رونما ہوئے تھے۔ ایسا کرنے کے لیے، آپ کو ایک کلاس بنانے کی ضرورت ہے جس میں کسی بھی سرور تھریڈ کے ساتھ آخری ایکشن کو اعلان کردہ فہرست میں داخل کیا جائے گا، اور اگر فہرست پہلے سے بھری ہوئی ہے (یعنی پہلے ہی 10 ہیں)، تو پہلی کو حذف کر کے شامل کریں۔ آخری جو آیا. اس فہرست کے مواد کو ایک نئے کنکشن کے ذریعے موصول کرنے کے لیے، سرور تھریڈ بناتے وقت، آؤٹ پٹ اسٹریم میں، آپ کو انہیں کلائنٹ کو بھیجنا ہوگا۔ یہ کیسے کرنا ہے؟ مثال کے طور پر، اس طرح:
public void printStory(BufferedWriter writer) {
// ...
}
سرور تھریڈ پہلے ہی اسٹریمز بنا چکا ہے اور آؤٹ پٹ سٹریم کو بطور دلیل پاس کر سکتا ہے۔ اگلا، آپ کو بس ہر وہ چیز پاس کرنے کی ضرورت ہے جسے تلاش کے چکر میں نئے کلائنٹ کو منتقل کرنے کی ضرورت ہے۔ نتیجہ: یہ صرف بنیادی باتیں ہیں، اور زیادہ امکان ہے کہ یہ چیٹ آرکیٹیکچر حقیقی ایپلی کیشن بناتے وقت کام نہیں کرے گا۔ یہ پروگرام تعلیمی مقاصد کے لیے بنایا گیا تھا اور اس کی بنیاد پر میں نے دکھایا کہ آپ کس طرح کلائنٹ کو سرور کے ساتھ بات چیت کر سکتے ہیں (اور اس کے برعکس)، کئی کنکشنز کے لیے یہ کیسے کیا جائے، اور یقیناً، یہ ساکٹ پر کیسے ترتیب دیا جاتا ہے۔ ذرائع کو ذیل میں دوبارہ ترتیب دیا گیا ہے، اور جس پروگرام کا تجزیہ کیا جا رہا ہے اس کا سورس کوڈ بھی منسلک ہے۔ مضمون لکھنے کا یہ میرا پہلا تجربہ ہے) آپ کی توجہ کا شکریہ :)
  1. جاوا انٹرپرائز میں سوچنا، بروس ایکل ایٹ کے ذریعہ۔ ال۔ 2003
  2. جاوا 8، مکمل گائیڈ، ہربرٹ شیلڈٹ، 9واں ایڈیشن، 2017 (باب 22)
  3. ساکٹ کے بارے میں جاوا مضمون میں ساکٹ پروگرامنگ
  4. سرکاری دستاویزات میں ساکٹ
  5. سرکاری دستاویزات میں سرور ساکٹ
  6. GitHub پر ذرائع
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION