初学JAVA,在做一个网络通信的练习,写了段代码,基本上是没什么问题
但是当我关闭客户端窗口时,服务器端跳出如下异常:
java.net.SocketException: Connection reset
我想应该是我里面用了个无限循环来输出用户端的输入信息的关系
因为没有设定弹出这个循环的条件,而当客户端关闭后,连接就断开了,但是循环还是继续,这样就取不到readLine的值了
问题是,我不知道要如何判断客户端已关闭,跳出这个循环,求教各位高手服务器端代码:
import java.io.*;
import java.net.*;public class MyTCP {
private ServerSocket server;
private Socket socket;
private InputStream input;
private BufferedReader reader; public void getServer() {
try {
server = new ServerSocket(8998);
System.out.println("服务器套接字创建成功");
System.out.println("等待客户机的连接");
socket = server.accept();
input=socket.getInputStream();
reader = new BufferedReader(new InputStreamReader(input));
getClientMessage();
reader.close();
input.close();
socket.close();
server.close();
} catch (Exception err) {
err.printStackTrace();
}
} private void getClientMessage() {
try {
//就是这里,我不知道要如何在客户端关闭后跳出这个循环,求教高手
while (true) {
String message = reader.readLine();
System.out.println("客户机:" + message);
}
} catch (IOException err) {
err.printStackTrace();
}
} public static void main(String[] args) {
MyTCP tcp = new MyTCP();
tcp.getServer();
}
}客户端代码:
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;public class MyClient extends JFrame {
private static final long serialVersionUID = 20101021L;
private Socket socket;
private PrintWriter writer;
private JTextArea textArea = null;
private JTextField textField = null; public MyClient(String title) {
super(title);
init();
} private void init() {
Container container = this.getContentPane();
this.setSize(200, 200);
this.setVisible(true);
container.add(getTextArea(), BorderLayout.NORTH);
container.add(getTextField(), BorderLayout.SOUTH);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
} private JTextArea getTextArea() {
if (textArea == null) {
textArea = new JTextArea();
}
return textArea;
} private JTextField getTextField() {
if (textField == null) {
textField = new JTextField();
textField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg) {
String message = textField.getText();
writer.println(message);
textArea.append(message + "\n");
textField.setText("");
}
});
}
return textField;
} private void connect() {
textArea.append("尝试连接……\n");
try {
socket = new Socket("192.168.1.2", 8998);
writer = new PrintWriter(socket.getOutputStream(), true);
textArea.append("完成连接\n");
} catch (Exception err) {
err.printStackTrace();
}
} public static void main(String[] args) {
MyClient client = new MyClient("向服务器送数据");
client.connect();
}
}

解决方案 »

  1.   

    我上大学那会儿写过一个,你可以下载了看看。
    http://download.csdn.net/source/1039605
      

  2.   

    在你文字那里加上一个判断
    if (reader.ready()) {while (true) {
         String message = reader.readLine();
         System.out.println("客户机:" + message);
    }
      

  3.   

     while (true) {
     你这样肯定会一直执行的。楼上的可以解决你的问题
      

  4.   

    修改你服务端的getClientMessage()方法代码如下:private void getClientMessage() {
            try {
                //就是这里,我不知道要如何在客户端关闭后跳出这个循环,求教高手
                while (true) {
                
                 if(!this.reader.ready()){
                 break;
                 }
                    String message = reader.readLine();
                    System.out.println("客户机:" + message);
                }
            } catch (IOException err) {
                err.printStackTrace();
            }
        }修改你客户端代码如下:package client;import java.awt.BorderLayout;
    import java.awt.Container;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.net.Socket;import javax.swing.JFrame;
    import javax.swing.JTextArea;
    import javax.swing.JTextField;
    public class MyClient extends JFrame {
    private static final long serialVersionUID = 20101021L;
        private Socket socket;
        private PrintWriter writer;
        private JTextArea textArea = null;
        private JTextField textField = null;    public MyClient(String title) {
            super(title);
            init();
        }    private void init() {
            Container container = this.getContentPane();
            this.setSize(200, 200);
            this.setVisible(true);
            container.add(getTextArea(), BorderLayout.NORTH);
            container.add(getTextField(), BorderLayout.SOUTH);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }    private JTextArea getTextArea() {
            if (textArea == null) {
                textArea = new JTextArea();
            }
            return textArea;
        }    private JTextField getTextField() {
            if (textField == null) {
                textField = new JTextField();
                textField.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent arg) {
                        String message = textField.getText();
                        writer.println(message);
                        textArea.append(message + "\n");
                        textField.setText("");
                    }
                });
            }
            return textField;
        }    private void connect() {
            textArea.append("尝试连接……\n");
            try {
                socket = new Socket("127.0.0.1", 8998);
                writer = new PrintWriter(socket.getOutputStream(), true);
                textArea.append("完成连接\n");
            } catch (Exception err) {
                err.printStackTrace();
            }
        }
        
        public void exit() {
         try {
         this.socket.shutdownOutput();
    this.socket.close();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
        }    public static void main(String[] args) {
        
        
            MyClient client = new MyClient("向服务器送数据");
            Runtime.getRuntime().addShutdownHook(new Closer(client) {
    public void run() {
    client.exit();
    }
    });
            
            client.connect();
            
            
            
        }}
    abstract class Closer extends Thread{
    protected MyClient client;
    public Closer(MyClient client){
    this.client=client;
    }

    }
    二楼的想法是对的,但方法不对,reader.ready()的判断不能放在while(true)循环的外面,而应该放在里面,如果reader.ready()返回false,则跳出while循环。
      

  5.   

    我去试了下,好像不对啊
    我又想了下,我这边是等待客户端输入后才会有输入输出流,那么这个ready在这过程中就执行了,所以用户还没输入,这循环就跳出了
      

  6.   

    我刚又去试了下addShutdownHook,奇怪的是当关闭客户端窗口时,服务器端就会无限循环输出null,这是为什么??我果然还是无法理解addShutdownHook
      

  7.   

    在服务端这边增加了一个客户机状态status的成员变量。
    在getClientMessage()方法中的判断条件增加对客户机状态的判断。
    代码如下:/**
         * 客户机状态
         * 0为未连接
         * 1为已连接
         */
        private int status=0;
        private void getClientMessage() {
            try {
                //就是这里,我不知道要如何在客户端关闭后跳出这个循环,求教高手
                while (true) {
                
                 if(!this.reader.ready() && this.status==1){
                 break;
                 }
                 status=1;
                    String message = reader.readLine();
                    System.out.println("客户机:" + message);
                }
                status=0;
            } catch (IOException err) {
                err.printStackTrace();
            }
        }
    那个addShutdownHook你可以理解为程序退出的时候要执行的动作。一般用来做一些清理工作,如关闭流等。
      

  8.   

    虽然很感谢,但是还是有问题
    我这边是等待客户端输入后把这内容传给服务器,但是并不意味着客户端只输入一次。
    加入了这个status后只能保证第一次输入的内容,然后这个status就被赋值1了,那么在等待下一次用户输入的时候,这个循环就跳出了。受到亲的启发后,我在客户端添加了一个static的status,在关闭钩子的线程里面改变这个status的值
    然后在服务器端这个无限循环里面加入根据status来进行判断循环是否break的条件,但是奇怪的是和我原来测试addShutdownHook情况一样,输出了无限null。= =
    这是为什么。果然对于addShutdownHook的理解还不够啊客户端更改如下:
    public static boolean clientStatus=false;
    private void exit() {
    try {
    clientStatus=true;
    socket.shutdownOutput();
    writer.close();
    socket.close();
    } catch (Exception err) {
    err.printStackTrace();
    }
    } private Thread close() {
    Thread thread = new Thread(new Runnable() {
    public void run() {
    MyClient.this.exit();
    }
    });
    return thread;
    } public static void main(String[] args) {
    MyClient client = new MyClient("向服务器送数据");
    client.connect();
    Runtime.getRuntime().addShutdownHook(client.close());
    }服务器端增加循环退出判断条件:
    private void getClientMessage() {
    try {
    while (true) {
    if (MyClient.clientStatus) {
    break;
    }
    String message = reader.readLine();
    System.out.println("客户机:" + message);
    }
    } catch (IOException err) {
    System.out.println("客户机关闭");
    }
    }