我自己写了一个小Server负责接受这个Socket连接发送的数据。
Client的Socket代码如下,每隔1秒向Server输出一些信息,
Server接受数据的时候不会给我输出信息。
现在的问题就是,假如Server突然关闭,我这边显示Client仍然在输出数据,不会抛出异常,这有点有违常理啊。C++的话,会马上抛出异常的。我就是想捕获这个异常,然后进行我的逻辑处理。可能是我Java网络编程理解的不是很好,还是思路问题。搭建帮忙讨论下。Client Socket源码  * @param args
 */
public static void main(String[] args) {
Socket server;
try {
server = new Socket(InetAddress.getByName("127.0.0.1"), 8888);
server.setKeepAlive(true);
//获取输入输出流
PrintStream ps = new PrintStream(server.getOutputStream(), false, "UTF-8");    
//BufferedReader in = new BufferedReader(new InputStreamReader(server.getInputStream()));
int i = 0;
while(true) {
System.out.println("server.isConnected()=" + server.isConnected());
System.out.println("server.isOutputShutdown()=" + server.isOutputShutdown());
System.out.println("hello" + i); ps.println("hello" + i); //自动在末尾加入分隔符
ps.flush();
i++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Server的源码import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;/**
 * 
 * @author Administrator
 * 使用TCP协议的服务器Demo
 */
public class SdServer { boolean started = false; //服务器是否启动
ServerSocket ss = null; //服务器对象
private static int port = 8888; //服务器监听的端口 private static final String LS = System.getProperty("line.separator"); public static void main(String[] args) { //根据传入的参数动态改变服务器的监听端口
if(args.length != 0) {
port = Integer.parseInt(args[0]);
} System.out.println("Service begins...");
new SdServer().start();
} public void start() { try {
ss = new ServerSocket(port);
started = true;
} catch (BindException e) {
System.out.println("The port has been used...");
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
} try {
while(started) {
Socket s = ss.accept(); //创建阻塞模式的服务器
Client c = new Client(s);
System.out.println("a client connected!");
new Thread(c).start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} /**
 * 
 * @author Administrator
 * 客户端类
 */
class Client implements Runnable { private Socket s;
private DataInputStream dis = null; //获取数据输入流
private DataOutputStream dos = null; //获取数据 BufferedReader in =  null; //获取缓存流的Reader
BufferedWriter out = null; //获取缓存流的Writer private boolean bConnected = false; //客户端是否正常连接 private boolean isFileWriting = false; //是否读写文件 public Client(Socket s) { this.s = s; try {
dis = new DataInputStream(s.getInputStream());
in = new BufferedReader(new InputStreamReader(dis,"utf-8")); dos = new DataOutputStream(s.getOutputStream());
out = new BufferedWriter(new OutputStreamWriter(dos)); bConnected = true; } catch (IOException e) {
e.printStackTrace();
}
} public void run() { //获取刘异常
if(!bConnected) {
return;
} try { System.out.println("*****************************************************");
DateFormat df=new SimpleDateFormat("yyyy-MM-dd EE hh:mm:ss");  //打印连接时间及客户端信息
System.out.println("Time:" + df.format(new Date())); 
System.out.println("Client IP:" + s.getLocalAddress().getHostAddress()); //开始输出获取的信息
System.out.println("Receive Msg:"); String str = ""; int i = 1;
File file = new File(i + ".txt"); while(str != null) { //客户端异常关闭,则这里会抛出一个IOException异常
str = in.readLine();
//str = new String(str.getBytes("UTF-8"),"UTF-8");
System.out.println("消息:" + str); //是否写入文件
if(isFileWriting) {
boolean flag = false; if(!file.exists()) { //不存在则创建文件
flag = file.createNewFile();
} else {
flag = true;
} if(flag) {
FileOutputStream fos = new FileOutputStream(file,true);
fos.write(str.getBytes("UTF-8"));
fos.flush();
fos.close();
}
}

out.write("copy your word" +  LS);
out.flush(); } System.out.println("Connection over"); } catch(SocketException e){             
System.out.println("Client closed the socket exception!");
bConnected = false;
//e.printStackTrace();                       
//System.exit(1);            
}catch (EOFException e) {
System.out.println("End of file exception!");
bConnected = false;
} catch (IOException e) {
System.out.println("IO Exception!");
e.printStackTrace();
bConnected = false;
} finally {
try { //简单释放下资源,其他流的资源在此处不做释放
if(in != null) in.close();
if(out != null) out.close();
if(s != null) s.close(); } catch (IOException e1) {
e1.printStackTrace();
System.out.println("Thread closed Exception.");
}
} System.out.println("*****************************************************");
} }
}

解决方案 »

  1.   

    client端的连接以及获取输出流均不在循环while里,你想报什么错?
      

  2.   

    如果server端从连接到断开,那么按照你写的代码,肯定输出信息发生变化,起码server.isConnected()就不一样。
      

  3.   


    server = new Socket(InetAddress.getByName("127.0.0.1"), 8888);
    server.setKeepAlive(true);
    //获取输入输出流
    PrintStream ps = new PrintStream(server.getOutputStream(), false, "UTF-8");   
    放到while循环里,同时在while循环的最后加上server.close();
      

  4.   

    回复大家。
    以前的系统是使用C#连接的。需要建立一个和Socket的长连接,不断查询数据,然后发给Server端。所以把server = new Socket(InetAddress.getByName("127.0.0.1"), 8888),放在while外面,模拟socket常链接。
    以前的代码,里面没有读取服务器的返回信息,所以服务器应该是不做应答的,这个我不确定。只是我这边会有一个接口,让对方调用,如果对方访问这个接口,我就会停止数据发送。之所以要捕获这个异常,原因是因为我通过一张hashtable维护要通讯的的serverip,但是如果远程的server意外的宕机或重启,我这边仍然会发送数据,积少成多,我们这边的服务器怕是顶不住了。。
    所以想捕获这个连接断开这个异常。to:mouer如果不麻烦的话,你运行我的代码。然后在停止SdServer程序,就可以看到我的Client程序中
     System.out.println("server.isConnected()=" + server.isConnected());
    打印信息是没有变化的。因为PrintStream在发数据方面貌似是和socket脱离的。JDK中,提到,server.isCOnnected是不会重新连接一次判断是否socket连接仍然存在的。读取的还是刚开始连接时存储的值。
    可能是我输出流用的方式不对,或是怎样,麻烦大家讨论一下。我的情况很好模拟,你运行一下代码就知道了。
      

  5.   

    ss.close();这句放在 new Thread(c).start();之后不要放在 finally子句里就可以了具体理由暂时还无法解释
      

  6.   

    两个程序都运行后,断开Server的程序,你将在Clinet程序的控制台中看到让然在输出信息,没有任何变化。所以我很郁闷。
      

  7.   

    我决定,判断远程服务器是否意外宕机应该是很常见的一个情况。个人认为Socket应该就是一个管道,如果管子的一段断开了,应该发送数据就会失败还是其他。 不过Java现在封装的层次有点多,我没有阅读过源码,不知道它底层如何实现,希望大家可以集思广益,讨论一下。 
    网络编程这个东西,研究研究还是值得的。如果讨论出结果,我一定追分。
      

  8.   

      server.isConnected());server.isOutputShutdown());这些都是判断本地端的状况
    也没有找到其他好的API  找了一个替代的方案.把下面这段代码嵌入到你的java COde中.效果应该是你想要的.如果觉得行就结贴给分哈...呵呵
       try{
         server.sendUrgentData(0xFF); 
       }catch(Exception ex){
          ex.printStackTrace();
          System.out.println("链接断开");
          return;
       }  
      

  9.   

    如果在每次循环发消息之前先调用socket的sendUrgentData(int data)方法,是可以捕捉到服务器宕机的异常的
      

  10.   

    public static void main(String[] args) {
            Socket server;
            try {
                server = new Socket("127.0.0.1", 8888);
                server.setKeepAlive(true);
                //获取输入输出流
                PrintStream ps = new PrintStream(server.getOutputStream(), false, "UTF-8");    
                //BufferedReader in = new BufferedReader(new InputStreamReader(server.getInputStream()));
                int i = 0;
                while(true) {
                    try{
                        server.sendUrgentData(1);
                    }catch(IOException e){
                        System.out.println("Server Down");
                    }
                    System.out.println("server.isConnected()=" + server.isConnected());
                    System.out.println("server.isOutputShutdown()=" + server.isOutputShutdown());
                    System.out.println("hello" + i);                ps.println("hello" + i);                                    //自动在末尾加入分隔符
                    ps.flush();
                    i++;
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            } catch (UnknownHostException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }这样就可以看到捕捉出异常了
      

  11.   

    你和lancijk说的是不是同一回事?
    我试过了,应该可以的。
      

  12.   

    客户端报异常是有条件的那是因为客户端在服务器端关闭之后还在读取getInputStream()的数据所以才抛异常,而你的程序根本就没有从服务器端读取数据所以没有异常。
      

  13.   

    try{
    socket.sendUrgentData(0xFF);
    }catch(Exception ex){
    sysout.println("已经断开");
    socket.close();
    }