当我正在学习java socket时,我已经在两个框架中进行了一次功能但非常简单的聊天:一个客户端和一个服务器。该应用程序只在本地和工作。但是当我关闭窗口时它不会停止(虽然我将WindowListener添加到两个框架类中):出了什么问题?
不要忘记先运行服务器,然后再运行客户端:只有在客户端连接后才会显示这两个帧。
这是SimpleSocketFrame.java(两个框架的基类):
package com.loloof64.java_se.simple_socket;
import java.awt.GridLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public abstract class SimpleSocketFrame extends JFrame {
public SimpleSocketFrame() {
setTitle(getFrameTitle());
setLayout(new GridLayout(0, 1));
messageToAddField = new JTextField(30);
messageToAddField.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER){
if ( ! messageToAddField.getText().isEmpty()) {
addMessage(messageToAddField.getText());
messageToAddField.setText("");
}
}
}
});
printedMessagesArea = new JTextArea(10,30);
printedMessagesArea.setEditable(false);
add(messageToAddField);
add(printedMessagesArea);
pack();
}
protected abstract void addMessage(String s);
protected abstract String getFrameTitle();
private static final long serialVersionUID = -5861605385948623162L;
protected JTextArea printedMessagesArea;
private JTextField messageToAddField;
}
这是服务器应用程序类:SimpleSocketServer.java
package com.loloof64.java_se.simple_socket;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JOptionPane;
public class SimpleSocketServer extends SimpleSocketFrame {
public SimpleSocketServer(){
super();
setTitle("Simple Server");
try {
serverSocket = new ServerSocket(12345);
relatedSocket = serverSocket.accept();
outStream = new PrintStream(relatedSocket.getOutputStream());
isr = new InputStreamReader(relatedSocket.getInputStream());
inStream = new BufferedReader(isr);
final InStreamRunnable inStreamRunnable = new InStreamRunnable();
Thread inStreamReaderThread = new Thread(inStreamRunnable);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent evt) {
try {
inStream.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
outStream.close();
try {
relatedSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
inStreamRunnable.stop();
System.exit(0);
}
});
inStreamReaderThread.start();
} catch (IOException e) {
JOptionPane.showMessageDialog(this, "Could not create the server !!!",
"Fatal error", JOptionPane.ERROR_MESSAGE);
System.exit(1);
e.printStackTrace();
}
}
private class InStreamRunnable implements Runnable {
@Override
public void run() {
while (weMustGoOn){
String line;
try {
line = inStream.readLine();
printedMessagesArea.setText(printedMessagesArea.getText()+line+"\n");
} catch (IOException e) {
}
}
}
public void stop(){
weMustGoOn = false;
}
private boolean weMustGoOn = true;
}
@Override
protected void addMessage(String s) {
s = "Serveur> "+s;
outStream.println(s);
printedMessagesArea.setText(printedMessagesArea.getText()+"Client> "+s+"\n");
}
@Override
protected String getFrameTitle() {
return "Simple Server";
}
public static void main(String[] args) {
new SimpleSocketServer().setVisible(true);
}
private static final long serialVersionUID = 4288994465786972478L;
private Socket relatedSocket;
private ServerSocket serverSocket;
private PrintStream outStream;
private InputStreamReader isr;
private BufferedReader inStream;
}
这是客户端类:SimpleSocketClient.java
package com.loloof64.java_se.simple_socket;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.Socket;
import javax.swing.JOptionPane;
public class SimpleSocketClient extends SimpleSocketFrame {
public SimpleSocketClient(){
try {
socket = new Socket(InetAddress.getLocalHost(), 12345);
outStream = new PrintStream(socket.getOutputStream());
isr = new InputStreamReader(socket.getInputStream());
inStream = new BufferedReader(isr);
final InStreamRunnable inStreamRunnable = new InStreamRunnable();
Thread inStreamReaderThread = new Thread(inStreamRunnable);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent evt) {
try {
inStream.close();
} catch (IOException e2) {
e2.printStackTrace();
}
try {
isr.close();
} catch (IOException e1) {
e1.printStackTrace();
}
outStream.close();
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
inStreamRunnable.stop();
System.exit(0);
}
});
inStreamReaderThread.start();
} catch (IOException e) {
JOptionPane.showMessageDialog(this, "Could not create the client !!!",
"Fatal error", JOptionPane.ERROR_MESSAGE);
System.exit(1);
e.printStackTrace();
}
}
public static void main(String[] args) {
new SimpleSocketClient().setVisible(true);
}
private class InStreamRunnable implements Runnable {
@Override
public void run() {
while (weMustGoOn){
String line;
try {
line = inStream.readLine();
printedMessagesArea.setText(printedMessagesArea.getText()+line+"\n");
} catch (IOException e) {
}
}
}
public void stop(){
weMustGoOn = false;
}
private boolean weMustGoOn = true;
}
@Override
protected void addMessage(String s) {
s = "Client> "+s;
outStream.println(s);
printedMessagesArea.setText(printedMessagesArea.getText()+s+"\n");
}
@Override
protected String getFrameTitle() {
return "Simple Client";
}
private static final long serialVersionUID = 5468568598525947366L;
private Socket socket;
private PrintStream outStream;
private InputStreamReader isr;
private BufferedReader inStream;
}
答案 0 :(得分:2)
您应该在finally
和try
之后添加catch
块以关闭套接字,之后您可以通过系统退出方法关闭程序。
答案 1 :(得分:2)
当您关闭正在无限期阻止的Readers
时尝试关闭网络输入JFrame
时,程序不会停止。 BufferedReader
和InputStreamReader
个对象无法关闭,因为客户端线程在等待服务器响应的readLine
调用中被阻止
line = inStream.readLine();
注释或删除:
inStream.close();
和
isr.close();
关闭Socket
流就足够了。
旁白:在与多线程网络应用程序的Swing组件交互时,请始终使用SwingWorker。 SwingWorkers
旨在与Swing组件正确交互。