初学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();
}
}
但是当我关闭客户端窗口时,服务器端跳出如下异常:
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();
}
}
http://download.csdn.net/source/1039605
if (reader.ready()) {while (true) {
String message = reader.readLine();
System.out.println("客户机:" + message);
}
你这样肯定会一直执行的。楼上的可以解决你的问题
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循环。
我又想了下,我这边是等待客户端输入后才会有输入输出流,那么这个ready在这过程中就执行了,所以用户还没输入,这循环就跳出了
在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你可以理解为程序退出的时候要执行的动作。一般用来做一些清理工作,如关闭流等。
我这边是等待客户端输入后把这内容传给服务器,但是并不意味着客户端只输入一次。
加入了这个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("客户机关闭");
}
}