2013-03-27 47 views
0

当我学习java套接字时,我已经在两个框架中进行了功能性但非常简单的聊天:一个客户端和一个服务器。该应用程序只是本地和工作。但是,当我关闭窗口时它不会停止(尽管我将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

这对于客户端和服务器都是一样的问题吗? – Austin 2013-03-27 23:58:20

+0

是的,两个框架都不能关闭。 – loloof64 2013-03-27 23:59:28

+0

运行守护程序线程时,系统不会退出 – MadProgrammer 2013-03-28 02:42:01

回答

2

当您试图关闭网络输入Readers时,程序不会停止,因为它将关闭无限期阻止的JFrameBufferedReaderInputStreamReader对象不能关闭作为客户端线程被阻塞在该readLine呼叫被从服务器等待响应

line = inStream.readLine(); 

注释掉或删除:

inStream.close(); 

isr.close(); 

只需关闭Socket即可。

Aside:与多线程网络应用程序的Swing组件进行交互时,请始终使用SwingWorkerSwingWorkers旨在与Swing组件正确交互。

+0

这是工作。另外,我将用SwingWorkers替换简单的线程。 – loloof64 2013-03-28 08:07:29

+0

此外,它是否仅仅意味着当我调用isr.close()时,我正在等待查找不可用的锁? – loloof64 2013-03-28 11:39:48

+0

相反,您正在等待'close'中的'Reader'中的锁“信号量”,因为您正在等待来自客户端/服务器的响应,所以从未收到通知。如此有效,这是一个僵局。 – Reimeus 2013-03-28 11:54:46

2

您应该在后添加finally块和catch关闭套接字,然后您可以通过系统退出方法关闭您的程序。

+0

是的,您是对的:我在计算机的代码上添加了最后的子句。 – loloof64 2013-03-28 08:08:27

相关问题