ورود

View Full Version : تشخیص کانکشن شکسته در SocketServer , socket



MSHService
چهارشنبه 30 مهر 1393, 11:36 صبح
با درود و ادب
منظزورم از کانکشن شکسته ، کانشکنیه که کلاینت یهو کابلش قطع بشه.
سرور چطور باید بفهمه؟!
من کدهای زیر رو نوشتم یه چند باز جواب داد ولی دستکاریش کردم خراب شد!!

فرض کردم کلاینتم Telnet هست و کلاینتمو خودم ننوشتم :)) اگر کلاینتمو خودم بنویسم که راحتم! ولی در این حالت نمیدونم.

چطور میتونم یه KeepAlive یی درست کنم روی سرور که روی تلتنت نشون داده نشه و بشه فهمید که کانکشن شکسته شده(منظورم کابل کلاینت قطع شده و یا توی Vmware شبکه disable شده)

کمک :)


package TEST;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
*
* @author me-sharifi
*/
public class MyTestServer {

private static ServerSocket ss;
private static Socket s ;
private static InputStream in;

private static PrintWriter mOut;

private static BufferedReader mSocketReader;

public static void main (String[] args){

try {
ss = new ServerSocket(2222);


} catch (IOException ex) {
System.err.println("ERR Exception : "+ex.getMessage());
}

for (;; ) {
try {
s = ss.accept();
System.out.println("Client Accepted : " + s);
mOut = new PrintWriter(
new OutputStreamWriter(s.getOutputStream()) );
// mSocketReader = new BufferedReader(
// new InputStreamReader(s.getInputStream()) );
mOut.println("WELOME : "+s);
mOut.flush();

s.setKeepAlive(true);


CheckClientAliveT ca = new CheckClientAliveT(s);

WorkerThread wt = new WorkerThread(s);


ca.start();
wt.start();

} catch (IOException ex) {
Logger.getLogger(MyTestServer.class.getName()).log (Level.SEVERE, null, ex);
System.err.println("ERR run Exception : "+ex.getMessage());
}
}
}
public static class WorkerThread extends Thread{
private Socket mSocket;
private BufferedReader mIn;
private PrintWriter mOut;

public WorkerThread(Socket socket) {
this.mSocket = socket;
try {

// Create character streams for the socket.
this.mIn = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
this.mOut = new PrintWriter(socket.getOutputStream(), true);





} catch (IOException ex) {
System.err.println("Eception ERR : WorkerThread :"+ex.getMessage());
}
}

@Override
public void run() {

// Accept messages from this client and broadcast them.
// Ignore other clients that cannot be broadcasted to.
while ((!isInterrupted())) {
// while ((true)) {
try{
String input = mIn.readLine();
if (input == null) {
return;
}
System.out.println("From Client : "+input);
mOut.println("MESSAGE " + ": " + input);
if(mOut.checkError())
System.out.println("mOut.checkError() TRUE");

} catch (IOException ex) {
System.err.println("Eception ERR run : "+ex.getMessage());
}
}
// System.err.println("Socket : "+mSocket+" Interupted!");
}

}
public static class CheckClientAliveT extends Thread{
private Socket mSocket;
private BufferedReader mIn;
private PrintWriter mOut;

public CheckClientAliveT(Socket socket) {
this.mSocket = socket;
try {

this.mOut = new PrintWriter(socket.getOutputStream(), true);
this.mIn = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
// this.mOut = new PrintWriter(socket.getOutputStream());

} catch (IOException ex) {
System.err.println("Eception ERR : SendThread :"+ex.getMessage());
}
}

@Override
public void run() {
// for (int i = 0; (i < 1000) && (!isInterrupted()) ; i++) {
for (int i = 0; (i < 100) ; i++) {


mOut.println("Send " + ": " +i);

if(mOut.checkError())
System.out.println("Broken Connection" );

try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
Logger.getLogger(MyTestServer.class.getName()).log (Level.SEVERE, null, ex);


}
}

}
}
}

محمد فدوی
چهارشنبه 30 مهر 1393, 17:04 عصر
منظورت رو کامل متوجه نشدم ولی به نظرم یه راهش گذاشتن Timeout برای ServerSocket میتونه باشه.

cups_of_java
چهارشنبه 30 مهر 1393, 17:43 عصر
شما می تونی از isConnected روی سوکت استفاده کنی

http://stackoverflow.com/questions/14010194/detecting-socket-disconnection

http://stackoverflow.com/questions/19786394/detecting-socket-disconnect-using-java-tcp-keepalive

http://stackoverflow.com/questions/151590/how-to-detect-a-remote-side-socket-close

MSHService
پنج شنبه 01 آبان 1393, 07:30 صبح
درود دوستان و تشکر میکنم از پاسخ هاتون.

من همه این کارهایی رو که گفتید کردم! ولی نمیشه تشخیصش داد.

همین سورسی که من گذاشتم رو اگر اجرا کنید و اونوقت توی یه ماشینه دیگه ، یا توی vmware به اون وصل بشید ، میبینید بعد از Welcome هر 2 ثانیه یه پیامه Send 1 و ... تا اخر براتوم میاد.

حالا اگر شما یهو کابل کامپیوتری که به عنوان کلاینت هست (همون کامپیوتری که شما روش Telnet زدید و به سرور وصل شدید) رو قطع کنید یا disable کنید سرور نمیفهمه.

من از isConnected و .... دیگه هم استفاده کردم اما نشد!

و بعد دیدم راه حل فقط توی چک کردم استریم خروجی برای ERROR هست (خط 143 پست اول) ، چند بار جواب داد ، دیگه جواب نداد!!

خوده جاوا میگه از SeKeepAlive استفاده کن! درسته با setkeepAlive سرور میتونه بفهمه کلاینت قطع شده ، اما بعد از 2 ساعت! و این 2 ساعت هم سیستم عامل مشخص میکنه.

لطفا کمک :)


من اینو SO_KEEPALIVE is implemented in the OS network protocol stacks without sending any "real" data باید پیاده سازی کنم. (نه از دستور SetKeepAlive خود جاوا استفاده کنم)

cups_of_java
پنج شنبه 01 آبان 1393, 08:41 صبح
درسته keepAlive خود TCP به درد برنامه ها نمیخوره.

شما خودت باید با ارسال یه دیتای الکی دایمن خودت مثل keepAlive رفتار کنی. به این کار PING-PONG میگن. اینطوری بدون وابستگی به تنظیمات سیستم عامل و TCP و لایه سوکت جاوا، هروقت PING کردی PONG نیومد میگی قطع شده

MSHService
پنج شنبه 01 آبان 1393, 21:19 عصر
من الان از همین روش استفاده میکنم! و دارم یه داده الکی میفرستم ولی اگه یه کلاینتو من ننوشته یاشم (منظورم از telnet هم همین بود که کلاینت رو من ننوشتم!) نمیتونم همینطور دیتای الکی بفرستم!

یکی از دوستام توی C# این رو پیاده کرد! نه با این روشی که شما گفتید و و یا همین روشی که الان من استفاده میکنم!

لطفا کمک :)

ahmad.mo74
پنج شنبه 01 آبان 1393, 21:32 عصر
سلام، موقع read یا write کردن exception نمیده؟ امکان نداره نده یعنی اگر کانکشن قطع شده باشه و بخواید چیزی write یا read بکنید باید اکسپشن بده :متفکر:

MSHService
شنبه 03 آبان 1393, 06:51 صبح
کلا Exception که نمیده هیچ(ابته تو داکیومنتها هم ننوشته باید Exception بده) موقع رایت باید یه Error بده که با اون ارور باید هندل بشه اونم نمیده!!
در کد زیر
if(mOut.checkError())

System.out.println("Broken Connection" );


چند باری این قسمت کارکرد ولی دیگه کار نکرد :((

با سپاس از راهنمایی شما

negative60
شنبه 03 آبان 1393, 09:42 صبح
کلاً اين مسئله اي هست که بيشتر کسانی که سوکت نويسی ميکنند به اين نکته مهم توجه نميکنند که اگر ارتباط سوکتی به صورت نامتعارف قطع بشه هيچ پاسخی به سرور ارسال نميشه منم هم مدتها دنبال راه حل اين مشکل بودم که خوشبختانه به اين شکل (http://barnamenevis.org/showthread.php?451885-%D8%AA%D8%B4%D8%AE%D9%8A%D8%B5-%D8%AE%D8%B1%D9%88%D8%AC-%D9%86%D8%A7%D9%85%D8%AA%D8%B9%D8%A7%D8%B1%D9%81-(%D8%B3%D9%88%DA%A9%D8%AA-%D9%BE%D8%B1%D9%88%DA%AF%D8%B1%D9%85%DB%8C%D9%86%D A%AF)&p=2021575&viewfull=1#post2021575) حل شد قبل از اينکه اين راه حل رو پيدا کنم هر 2 دقيقه يکبار يک بايت به همه سوکت های آنلاين ارسال ميکردم که بعد از مدتی سوکت هايی که نامتعارف ديسکانت شده بودند بسته ميشدند.

MSHService
شنبه 03 آبان 1393, 10:34 صبح
دوست عزیز دقیقا همین چیزی بود که من میخواستم :لبخند:

حالا چطوری این کد رو بیارم توی برنامه جاوام؟!

negative60
شنبه 03 آبان 1393, 11:36 صبح
اين فکر کنم معادل همون کار رو انجام بده تست کنيد, بعد از بستن نامتعارف کلاينت چند دقيقه صبر کنيد اگر پاسخی در سرور دريافت شد مشکلتون حل شده.

ServerSocket servSock = new ServerSocket(9999);
Socket sock = servSock.accept();
sock.setSoTimeOut(1*60*1000); //1 minutes
sock.setKeepAlive(true);

MSHService
شنبه 03 آبان 1393, 13:24 عصر
متشکرم دوست عزیزم ، ولی این ، اون نیست !

این به سرور میگه وقتی کلاینت به مدت 1*60*1000 ثانیه ، ازش اطلاعات نیومد یه SocketTimeoutException بده.

من این رو قبلا هندل کردم

while (!isInterrupted()) {
try {
String message = mSocketReader.readLine();
if (message == null)
break; // Client closed the socket
processClientMessage(message);
} catch (SocketTimeoutException ste) {
System.out.println("SocketTimeoutException on "+mSocket.getPort()+
" : "+ste.getMessage());
}
}
برای این هندلش کردم که اگر کلاینت پیام نفرستاد بفهمم!

حالا شما حالتی رو فرض کنید که دوتا کلاینت (telnet) وصل هستن ، اولی توی Vmware و دومی توی همین کامپیوتری که سرور Run هست.
حالا اگر بعد از یک دقیقه هیچ کدوم از اینا چیزی نفرستند سرور میفهمه که اینا هیچکدومشون چیزی نفرستان (چون تو قسمت readLine خطای SocketTimeoutException رخ داده.)
اما کلاینتم vmwarم و Localم هردوشون زنده اند ولی داده ارسال نکردن. اینجاست که من باید اون پکت و یا یه چیزی بفرستم روی کلاینت، تا بفهمم کلاینتم مرده :)
من دنباله این پکته هستم که ببینم چیه و چطور توی جاوا پیاده سازیش کنم. (فرضم هم اینه که کلاینت ماله خودم نیست)

با سپاس از زحمات همه دوستان

MSHService
چهارشنبه 26 آذر 1393, 11:39 صبح
دوستان کسی این رو فهمید چه کار باید کنیم؟!