پیش نیاز:
ارتباط TCP در جاوا
Thread در جاوا (قسمت اول:مفاهیم اولیه Thread)
Thread در جاوا (قسمت دوم:ایجاد ترد با استفاده از روش بسط کلاس Thread)
Thread در جاوا (قسمت سوم:ایجاد ترد با استفاده از واسط Runnable)
پیاده سازی چت با استفاده از مالتی ترد:
در آموزش برقراری ارتباط از نوع TCP نمونه یک چت ساده پیاده سازی شد. در این برنامه موارد زیر وجود داشت که برای رفع آنها می بایست از تکنولوژی ترد استفاده شود:
- کلاینت شروع کننده و خاتمه دهنده چت بود بدین معنا که سرور نمی توانست قبل از اینکه پیامی از کلاینت دریافت کند اقدام به ارسال پیام نمیاد.
- مکالمه بصورت یک در میان بود یعنی کلاینت مطلبی را ارسال می کرد و خود در حالت شنود قرار می گرفت در طرف دیگر سرور که در حالت شنود بود پیام را دریافت نموده و به حالت ارسال تغییر وضعیت می داد.
- مکالمه با ارسال QUIT از طرف کلاینت خاتمه پیدا می کرد یعنی سرور قادر به خاتمه ارتباط نبود.
دلیل تمامی موارد بالا در این نکته نهفته است که برنامه ما در یک زمان عمل ارسال و دریافت را نمی توانست انجام دهد.
همانطور که قبلا اشاره شد برای ایجاد همزمانی در برنامه می بایست از ترد استفاده کرد در برنامه چت مورد نظر دو بخش اساسی وجود دارد:
- بخشی که مسئول دریافت اطلاعات از کاربر و ارسال آنها می باشد.
sendstring=inp.next();
output.writeUTF (sendstring);
- بخشی که مسئول دریافت اطلاعات از سمت ارسال کننده و نمایش آنها می باشد.
request = input.readUTF ();
System.out.println(request);
هر دو بخش بالا باید بصورت ترد هایی جداگانه ایجاد شوند. در زیر نحوه پیاده سازی این دو بخش آمده است لازم به ذکر است که هر دو از روش بسط کلاس ترد ساخته شده اند:
ارسال اطلاعات:
class send extends Thread
{
private DataOutputStream output;
public send(DataOutputStream s) throws Exception{
output=s;
}
public void run()
{
String sendstring="";
do{
Scanner inp = new Scanner(System.in);
try{
sendstring=inp.next();
output.writeUTF (sendstring);
}catch(IOException e){}
}while(true);
}
}دریافت اطلاعات:
class recv extends Thread
{
private DataInputStream input;
private DataOutputStream output;
public recv(DataInputStream s,DataOutputStream t) throws Exception{
input=s;
output=t;
}
public void run()
{
String request="";
do{
try{
request=input.readUTF();
if (request.equals("Q")){
output.writeUTF("Q");
System.exit(0);}
System.out.println("CLIENT:"+request);
}catch(IOException e){}
}while(true);
}
}
ما بقی آنچه در برنامه مشاده می کنید مانند همان مثال اولیه می باشد. فقط کافیست بعد از انجام مراحل اولیه که همان ایجاد سوکت - ایجاد ارتباط – و معرفی Stream های ورودی و خروجی دو ترد از انواع ایجاد شده در بالا تعریف نمود:
send Tsend =new send(output);
recv Trecv=new recv(input,output);
Stream های ورودی و خروجی ایجاد شده به عنوان پارامتر به این دو ترد ارسال می شود. حال کافیست دو ترد مورد نظر را اجرا کنیم:
Tsend.start();
Trecv.start();برای خاتمه برنامه از متد System.exit(0) استفاده شده است یعنی چه کلاینت و چه سرور با دریافت کارکتر Q کل سیستم را متوقف می کنند. این روش به غیر از ساده سازی آموزش بالا استفاده دیگری برای ما ندارد چون طبیعیست قرار نیست کا برنامه ما با بسته شدن ارتباط دو نفر به طور کامل متوقف شود!!! چاره چیست ؟؟ استفاده از حلقه While و گذاشتن شرط تا این مرحله جوابگو نمی باشد چرا که به فرض دریافت Q در قسمت مربوط به دریافت اطلاعات فقط این بخش را می توانیم متوقف کنیم(اگر شرطWhile باشد) و بخش مربوط به ارسال همچنان فعال باقی می ماند چون اصولا دریافت و ارسال دو ترد جداگانه هستند چاره کار در این است که بعد از دریافت Q علاوه بر غیر فعال کردن ترد دریافت ترد ارسال نیز از درون ترد دریافت غیر فعال شود .
مشکل دسترسی به ترد ارسال از درون ترد دریافت با فرستادن ترد ارسال به عنوان پارامتر به ترد دریافت حل می شود. تنها سوالی که در اینجا مطرح است چگونگی توقف یک ترد می باشد که در قسمت بعدی که بررسی متد های مربوط به ترد ها می باشد به توضیح آن می پردازیم.
کد سرور و کلاینت مربوط به این آموزش ضمیمه می باشد.