2013-12-05 2 views
0

Я до сих пор не понимал, что моя кнопка отключения в моей программе не работает. Если у меня есть 3 клиента, и каждый из них отключит связь, тогда отключается только последний клиент. Как выбрать, какой экземпляр мне нужно закрыть? Если из 3-х пользователей, я хочу, чтобы удалить первый ..Как выбрать, какой поток нужно закрыть из нескольких потоков?

сервер:

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.PrintWriter; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.text.SimpleDateFormat; 
import java.util.Calendar; 
import java.util.HashSet; 
import java.util.Scanner; 
import java.util.Set; 

public class Server { 
    private Set<Socket> sockets = new HashSet<Socket>(); 
    private Set<String> names = new HashSet<String>(); 
    private Socket sock; 
    private static int port; 
    private Calendar cal = Calendar.getInstance(); 
    private SimpleDateFormat date = new SimpleDateFormat("dd/mm/yyyy hh:mm:ss"); 

    public Server(int input) { 
     port = input; 
    } 

    public static void main(String[] args) { 
     /* 
     * user defines port number, server initialized 
     */ 
     System.out.println("enter a port"); 
     Scanner input = new Scanner(System.in); 
     port = input.nextInt(); 
     new Server(port).go(); 
     input.close(); 
    } 

    public void go() { 
     try { 
      /* 
      * wait for connections, add connections to Set, setup streams per 
      * connection in new threads 
      */ 
      System.out.println("waiting for connetion"); 
      @SuppressWarnings("resource") 
      ServerSocket serverSocket = new ServerSocket(port); 
      while (true) { 
       sock = serverSocket.accept(); 
       sockets.add(sock); 
       Thread t = new Thread(new ClientHandler(sock)); 
       t.start(); 
       System.out.println("connected: " + sock.getInetAddress()); 
      } 
     } catch (IOException ex) { 
      ex.printStackTrace(); 
      System.out.println("server setup failed"); 
     } 
    } 

    class ClientHandler implements Runnable { 
     /* 
     * client handler sets up streams 
     */ 
     private BufferedReader in; 
     private PrintWriter out; 
     private String name; 

     public ClientHandler(Socket sock) { 
      try { 
       in = new BufferedReader(new InputStreamReader(
         sock.getInputStream())); 
       out = new PrintWriter(sock.getOutputStream(), true); 
      } catch (IOException e) { 
       e.printStackTrace(); 
       System.out.println("stream setup failed"); 
      } 
     } 

     @Override 
     public void run() { 
      /* 
      * First check if user exists, if true than close connection and 
      * warn user about name. Then relay message to all clients, if user 
      * DC's than remove the socket from the Set 
      */ 
      String message; 
      try { 
       name = in.readLine(); 
       if (names.contains(name)) { 
        System.out.println("duplicate name detected, removing.."); 
        out.println("choose new name and reconnect: " 
          + sock.getInetAddress()); 
        sock.close(); 
        sockets.remove(sock); 
       } else { 
        names.add(name); 
        System.out.println("Users active: " + names); 
        shout("user: " + name + " connected!" + " from " 
          + sock.getInetAddress()); 
       } 
       while ((message = in.readLine()) != null) { 
        /* 
        * call method which checks if user tries to enter a command 
        * such as /laugh or /roll, otherwise relay the message to 
        * all clients 
        */ 
        swich(message); 
       } 
      } catch (IOException ex) { 
       System.out.println("user disconnected: " + name + " " 
         + sock.getInetAddress()); 
       shout("user disconnected: " + name + " " 
         + sock.getInetAddress()); 
       names.remove(name); 
       remove(sock); 
      } 
     } 

     public synchronized void shout(String message) { 
      // send message to all clients in Set 
      for (Socket sock : sockets) { 
       try { 
        PrintWriter writer = new PrintWriter(
          sock.getOutputStream(), true); 
        writer.println(date.format(cal.getTime()) + " " + message 
          + "\n"); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 

      } 

     } 

     public void swich(String message) throws IOException { 
      // check if user calls a chat command 
      // otherwise shout message to all clients 
      switch (message) { 
      case "/disconnect": 
       out.println("disconnected"); 
       remove(sock); 
       break; 
      case "/laugh": 
       String[] laughs = { "HahHA!", "HAHAAH!!!!", "haaaaa!!!", 
         "hohohoohohahhaa!!!", "huehuehue!" }; 
       shout(name + " " + laughs[(int) (Math.random() * 5)]); 
       break; 
      case "/roll": 
       shout(name + " rolls " 
         + Integer.toString((int) ((Math.random() * 6) + 1))); 
       break; 
      case "kirby!": 
       shout("(>'-')> <('-'<) ^(' - ')^ <('-'<) (>'-')>"); 
       break; 
      default: 
       shout(message); 
       System.out.println("client says : " 
         + date.format(cal.getTime()) + message); 
      } 
     } 

    } 

    public void remove(Socket soc) { 
     try { 
      soc.close(); 
      sockets.remove(soc); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

} 

клиент:

import java.awt.BorderLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.PrintWriter; 
import java.net.Socket; 
import java.util.Scanner; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTextArea; 
import javax.swing.JTextField; 
import javax.swing.SwingUtilities; 

public class Client { 

    private JTextArea tArea; 
    private JTextField tField; 
    private JTextField portText; 
    private JTextField hostText; 
    private BufferedReader in; 
    private Socket sock; 
    private static PrintWriter out; 
    private static String name; 
    private String host; 
    private String port; 

    public static void main(String[] args) { 
     System.out.println("Enter username"); 
     Scanner input = new Scanner(System.in); 
     name = input.nextLine(); 
     input.close(); 
     new Client().go(); 

    } 

    public void go() { 
     /* 
     * build gui 
     */ 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       JFrame frame = new JFrame("hakobChat"); 
       JPanel topPanel = new JPanel(); 
       JLabel portLabel = new JLabel("port"); 
       JLabel hostLabel = new JLabel("host"); 
       portText = new JTextField(6); 
       hostText = new JTextField(12); 
       JButton connect = new JButton("connect"); 
       connect.addActionListener(new connectListener()); 
       JButton disconnect = new JButton("disconnect"); 
       disconnect.addActionListener(new disconnectListener()); 
       tField = new JTextField(30); 
       tField.addActionListener(new sendListener()); 
       tArea = new JTextArea(30, 50); 
       tArea.setEditable(false); 
       tArea.setLineWrap(true); 
       JScrollPane tScroll = new JScrollPane(tArea, 
         JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, 
         JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 
       JButton button = new JButton("send"); 
       button.addActionListener(new sendListener()); 
       topPanel.add(hostLabel); 
       topPanel.add(hostText); 
       topPanel.add(portLabel); 
       topPanel.add(portText); 
       topPanel.add(connect); 
       topPanel.add(disconnect); 
       frame.setSize(300, 500); 
       frame.setVisible(true); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.getContentPane().add(topPanel, BorderLayout.NORTH); 
       frame.getContentPane().add(tScroll, BorderLayout.CENTER); 
       frame.getContentPane().add(tField, BorderLayout.SOUTH); 
       frame.getContentPane().add(button, BorderLayout.EAST); 
       frame.pack(); 
      } 
     }); 
    } 

    public void setupNetwork(String host, int port) { 
     /* 
     * setup in and out stream send user name to server to check if 
     * duplicate start thread for incoming messages 
     */ 
     try { 
      sock = new Socket(host, port); 
      in = new BufferedReader(
        new InputStreamReader(sock.getInputStream())); 
      out = new PrintWriter(sock.getOutputStream(), true); 
      out.println(name); 
      showMessage("Connected!"); 
      showMessage("enter /laugh or /roll or kirby! for some fun!"); 
      Thread t = new Thread(new IncomingReader()); 
      t.start(); 
     } catch (IOException ex) { 
      ex.printStackTrace(); 
      showMessage("please enter valid network"); 
     } 
    } 

    class IncomingReader implements Runnable { 
     // receive messages from server 
     public void run() { 
      try { 
       String message = null; 
       while ((message = in.readLine()) != null) { 
        showMessage(message + "\n"); 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
       showMessage("choose new name and reconnect please"); 
      } 
     } 
    } 

    public synchronized void sendMessage(String message) { 
     try { 
      switch (message) { 
      case "/laugh": 
       out.println("/laugh"); 
       break; 
      case "/roll": 
       out.println("/roll"); 
       break; 
      case "kirby!": 
       out.println("kirby!"); 
       break; 
      default: 
       out.println("(" + name + ")" + ": " + message); 
      } 

     } catch (Exception e) { 
      e.printStackTrace(); 
      System.out.println("fail send message"); 
     } 
    } 

    public void showMessage(final String message) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       tArea.append(message + "\n"); 
       tArea.setCaretPosition(tArea.getDocument().getLength()); 
       // SetCaretPosition forces autos scroll 
      } 
     }); 
    } 

    class sendListener implements ActionListener { 
     // listens for user to trying to send a message 
     public void actionPerformed(ActionEvent ev) { 
      sendMessage(tField.getText()); 
      tField.setText(""); 
     } 
    } 

    class disconnectListener implements ActionListener { 
     public void actionPerformed(ActionEvent ev) { 
      try { 
       out.println("/disconnect"); 
      } catch (NullPointerException e) { 
       showMessage("not connected"); 
      } 
     } 
    } 

    class connectListener implements ActionListener { 
     public void actionPerformed(ActionEvent ev) { 
      host = hostText.getText(); 
      port = portText.getText(); 
      if (!host.equals("") && !port.equals("") && port.matches("[1-9]+")) { 
       // make sure user enters valid inputs 
       // before setting up network 
       setupNetwork(host, Integer.parseInt(port)); 
      } else { 
       showMessage("enter valid network credentials"); 
      } 
     } 

    } 

} 

Кроме того, как избежать этого "@SuppressWarnings (" ресурс ")". Если у меня нет этого затмения, выдается предупреждение, а serverSocket подчеркивается желтым.

+0

Две вещи. 1) Рассматривали ли вы использование карты от клиентов к потокам? 2) Вы уверены, что всегда закрываете поток, когда закончите с ним? –

+0

У меня есть проблемы с настройкой, как делать имена пользователей, и так, как я это делал, было довольно плохо: /, также я проверял дважды и уверен, что я закрыл все свои потоки – gallly

ответ

1

Необходимо сохранить Socket, используемый для клиента внутри ClientHandler.

Вы можете сделать это, просто добавив

private Socket sock; 

внутри ClientHandler, и добавив:

this.sock = sock; 

внутри своего конструктора.

В настоящее время вы используете сохраненный на сервере Socket, который всегда будет соседом последнего подключенного клиента, а не Socket, принадлежащим текущему клиенту.

+0

спасибо всем за быстрые ответы, я исправил его – gallly

1

Это всего лишь проблема обзора. Элемент Socket sock не должен быть частью класса Server. Он должен быть частью класса ClientHandler. Один на каждого клиента.

Смежные вопросы