2017-04-13 36 views
0

編輯!:我發現了錯誤,它在while循環中,我們不應該修改...它檢查連接是否以錯誤的方式關閉。 所以請,如果有任何mod讀取(我標記)...刪除。感謝和抱歉,造成任何麻煩。socket.Close()暫停程序(java)(請刪除)

我正在和Java進行TCP聊天,當我嘗試關閉一個套接字時,一個jFrame窗口的客戶端停止工作(加上CPU使用率激增)。 我使用NetBeans 8.1和jdk1.8.0_91。

我需要關閉連接並初始化它。 我做了一些研究,但仍然找不到任何東西......我錯過了什麼?

在此先感謝。

編輯:減少ChatThread代碼很多,也刪除coments和從其他.java一些行...,它仍然太長,我認爲。道歉。

代碼: Project Server時,Server.java包含:

import java.io.IOException; 
import java.net.InetSocketAddress; 
import java.net.ServerSocket; 
import java.net.Socket; 

public class Server { 

private static final String version = "v0.4(Curry) 07/04/17"; 
private static ServerSocket srvSocket; 

public static void main(String[] args) throws IOException { 
    int port = -1; 
    int maxConnections = 50; 

    Socket[] connections = new Socket[maxConnections]; 
    String[] users = new String[maxConnections]; 

    System.out.println("Chat Server - " + version + " por Marçal"); 

    switch (args.length) { 
     case 0: 
      port = 5667; 
      break; 
     case 1: 
      try { 
       port = Integer.parseInt(args[0]); 
      } catch (NumberFormatException e) { 
       System.out.println("Uso: java -jar chatserver.jar [puerto]"); 
       System.exit(-1); 
      } 
      break; 
    } 

    InetSocketAddress socketAddr = null; 
    socketAddr = new InetSocketAddress(port); 

    srvSocket = null; 
    try { 
     srvSocket = new ServerSocket(); 
     srvSocket.bind(socketAddr); 
    } catch (IOException e) { 
     System.out.println("Error: imposible conectar"); 
     System.exit(-1); 
    } 

    System.out.println("en línea, aceptando conexiones en el puerto " + port + " ...\n"); 

    int idSocket = 0; 
    while (srvSocket != null) { 
     try { 
      if (connections[idSocket] == null) { 

       Socket socket = srvSocket.accept(); 
       connections[idSocket] = socket; 

       if (idSocket % 2 == 0) { 
        users[idSocket] = "John Doe " + idSocket; 
       } else { 
        users[idSocket] = "Jane Doe " + idSocket; 
       } 
       System.out.println("Nueva conexión: id"+idSocket+" ["+connections[idSocket].getInetAddress()+":"+connections[idSocket].getPort()+"]"); 
       Thread t = new ChatThread(idSocket, maxConnections, connections, users[idSocket]); 
       t.start();      
      } 
      idSocket = (idSocket + 1) % maxConnections; 
     } catch (IOException e) { 
      System.out.println("Error: fallo E/S servidor"); 
      System.exit(-1); 
     } 
    } 
    srvSocket.close();}} 

Project Server時,ChatThread.java包含:

import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.net.Socket; 

public class ChatThread extends Thread { 

    private final int id; 
    private final int maxConnections; 
    private final Socket[] conns; 
    private final String[] users; 
    OutputStream salida; 
    InputStream entrada; 

public ChatThread(int idSocket, int maxConnections, Socket[] connections, String user) { 
    this.maxConnections = maxConnections; 
    this.id = idSocket; 
    this.conns = connections; 
    this.users = new String[this.maxConnections]; 
    this.users[this.id] = user;  
} 

public void run() { 
    try { 
     String buff;   
     salida = conns[id].getOutputStream(); 
     entrada = conns[id].getInputStream(); 

     salida.write("BLABLA".getBytes()); 

     conns[id].shutdownInput(); //No Halt 
     conns[id].shutdownOutput(); //Halt 
     salida.flush(); //Halt   
     salida.close(); //Halt 
     entrada.close(); //Halt   
     conns[id].close(); //Halt 
     } catch (IOException e) { 
     }}} 

項目客戶,Client.java包含: 包com.chat ;

import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.net.InetAddress; 
import java.net.InetSocketAddress; 
import java.net.Socket; 
import java.net.UnknownHostException; 

import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTextArea; 
import javax.swing.JTextField; 
import javax.swing.text.DefaultCaret; 

public class Client extends JFrame { 

private static final long serialVersionUID = 1L; 

private static final String version = "v0.4(Curry) 07/04/17"; 

private JFrame frmChat; 
private JTextField input; 
private JTextArea salida; 
private JScrollPane scrollPane; 

private static InetSocketAddress socketAddr; 
private static InputStream is; 
private static OutputStream os; 

static String text; 

public static void main(String[] args) { 
    Client window = new Client(args); 
    window.frmChat.setVisible(true); 

    try { 
     Socket cliSocket = new Socket(); 
     cliSocket.connect(socketAddr); 
     window.frmChat.setTitle("Chat " + version + " - " + cliSocket.getLocalAddress().toString() + " [" + cliSocket.getLocalAddress().getCanonicalHostName() + "]"); 

     is = cliSocket.getInputStream(); 
     os = cliSocket.getOutputStream(); 

     window.input.requestFocusInWindow(); 
     byte[] msg = new byte[100]; 
     String str; 
     text = ""; 
     do { 
      is.read(msg); 
      str = new String(msg); 
      window.salida.append(str); 
      msg = new byte[100]; 
     } while (!text.equals("SALIR")); 

     cliSocket.close(); 
     window.frmChat.dispose(); 
    } catch (IOException e) { 
     window.salida.setText(e.getMessage()); 
    } 
} 

public Client(String[] args) { 
    int port = -1; 
    switch (args.length) { 
     case 0: 
      System.out.println("Uso: java -jar chatclient.jar ip|host [puerto]"); 
      System.exit(0); 
      break; 
     case 1: 
      port = 5667; 
      break; 
     case 2: 
      try { 
       port = Integer.parseInt(args[1]); 
      } catch (NumberFormatException e) { 
       System.out.println("Error: debe especificarse un puerto"); 
       System.exit(-1); 
      } 
      break; 
    } 

    socketAddr = null; 
    try { 
     socketAddr = new InetSocketAddress(InetAddress.getByName(args[0]), port); 
    } catch (UnknownHostException e) { 
     System.out.println("Error: host no encontrado/sintaxis incorrecta"); 
     System.exit(-1); 
    } 

    initialize(); 
} 

private void initialize() { 
    frmChat = new JFrame(); 
    frmChat.setTitle("Chat"); 
    frmChat.setResizable(false); 
    frmChat.setBounds(100, 100, 441, 411); 
    frmChat.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frmChat.getContentPane().setLayout(null); 

    salida = new JTextArea(); 
    salida.setEditable(false); 
    salida.setBounds(10, 11, 414, 335); 

    DefaultCaret caret = (DefaultCaret) salida.getCaret(); 
    caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE); 

    scrollPane = new JScrollPane(salida, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); 
    scrollPane.setBounds(10, 11, 414, 335); 
    frmChat.getContentPane().add(scrollPane); 

    input = new JTextField(); 
    input.setBounds(10, 354, 414, 20); 
    frmChat.getContentPane().add(input); 
    input.setColumns(100); 

    input.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent arg0) { 
      text = input.getText().trim(); 
      try { 
       if (!text.equals("") && text != null) { 
        os.write(text.getBytes()); 
        os.flush(); 
       } 
      } catch (IOException e) { 
       salida.append("Error: no se puede enviar"); 
      } 
      input.setText(null); 
     }});}} 
+0

我要帶它,你的Swing GUI的被凍結,這意味着你的代碼是不繼Swing線程規則。我不確定其他人,但是我需要看到更多的代碼,儘可能接近您可以製作的[mcve],並且始終小到可以將您的問題作爲代碼格式的文本發佈,但卻足夠大以顯示我們的問題。 –

+0

拋出了什麼異常? – EJP

+0

沒有我意識到的異常,只有Swing GUI的凍結和CPU使用率增加,導致任何客戶端無法繼續寫入。 – maral04

回答

4

在這裏你的問題表現...

do { 
    is.read(msg); 
    str = new String(msg); 
    window.salida.append(str); 
    msg = new byte[100]; 
} while (!text.equals("SALIR")); 

你沒有注意到什麼是被is.read返回。這將在套接字在服務器端關閉後返回-1,這意味着它已到達「文件末尾」或者沒有更多內容要讀取。

因爲你基本上忽略了它,do-while循環可以自由運行,儘可能快,基本上消耗CPU週期並使客戶端無用。

重要的是要注意從套接字中讀取的字節數,因爲它會指出兩件事:1-當沒有剩下要讀的內容時,以及2-數組中有多少內容可用。這意味着你可以重用在每次迭代的陣列,像...

int read = -1; 
while ((read = is.read(msg)) != -1) { 
    str = new String(msg, 0, read); 
    if (str.equals("SALIR")) { 
     break; 
    } 
    window.salida.append(str); 
} 

現在,只要你將它添加到您的代碼,框架會閃爍並消失,因爲你已經關閉套接字在服務器端。

通常情況下,您在服務器線程中會讀取/寫入內容,並且只有在您向其發送「退出」命令時纔會退出,這意味着您的客戶端while-loop不會在第一條消息被讀取,但我猜這是你剛開始玩的時候。

如上所述,您的客戶端代碼違反了Swing的單線程特性,有關更多詳細信息,請參見Concurrency in Swing

有一些你可能會解決這個問題的方法,但是SwingWorker可能是最簡單之中見Worker Threads and SwingWorker更多細節

+0

感謝您的答案,是的,我有一個讀取/寫入服務器線程的循環,應退出「退出」一詞。也嘗試過你的代碼,並按照你說的工作,但在這種情況下,客戶端的內容不應該被修改...所以我可能會丟失在服務器部分導致從客戶端連續-1垃圾郵件的東西。我會在接下來的幾天繼續嘗試,如果有新的東西出現,請更新:) – maral04

+0

根據示例代碼,您的服務器沒有讀/寫循環,它會寫入消息,然後關閉流和套接字 – MadProgrammer