2017-09-06 126 views
0

我创建了一个基于服务器的聊天程序,该程序有多个工作线程,每个线程处理套接字上的客户端。它有一个服务器套接字将客户端传递给工作线程。Java使用客户端套接字的多个线程

public static void main(String[] args) { 
    ExecutorService executor = Executors.newFixedThreadPool(5); 
    ServerSocket serverSocket = null; 
    try { 
     serverSocket = new ServerSocket(4001); 
     System.out.println("Listening server"); 
     while (true) { 
      Socket socket = serverSocket.accept(); 
      System.out.println("Connected"); 
      Random rand= new Random(); 
      int port=4001+rand.nextInt(5); 
      Worker worker = new Worker(port); 
      executor.execute(worker); 
      System.out.println("Thread started"); 
      new PrintWriter(socket.getOutputStream(), true).println(port); 
      socket.close(); 
      System.out.println("Closed"); 
      // break; 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

} 

public class Worker implements Runnable { 

private int port; 
public Worker(int i) { 
    port=i; 
} 
@Override 
public void run() { 
    worker(); 
} 
private static Socket socket; 
private static PrintWriter out; 
private static BufferedReader in; 

private void worker() { 
    try { 
     ServerSocket serverSocket = new ServerSocket(port); 
     socket = serverSocket.accept(); 
     out = new PrintWriter(socket.getOutputStream(), true); 
     in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
     String line; 
     while ((line = in.readLine()) != null) { 
      System.out.println("Received: " + line); 
      switch (line) { 
       case ("Button Press"): 
        System.out.println("Handled button"); 
        out.println("Button acknowledged"); 
        break; 
       case ("Give me some data"): 
        System.out.println("Handled data"); 
        out.println("Have some data"); 
        break; 
      } 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } finally { 
     try { 
      out.close(); 
      in.close(); 
      socket.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

    } 
} 

这工作得很好,然而,问题是当我有由客户端的自动请求来检查消息和用户提供的相同类型的某些输入。这会导致冲突,因为实际方法需要运行几秒钟,并且如果接收到更多输入,则请求将不会被处理,因为它位于方法的中间。例如:

private static BufferedReader in; 
private static PrintWriter out; 
public static void main(String[] args) { 
    Main main=new Main(); 
    main.createWindow(); 
    try { 
     Socket init = new Socket(InetAddress.getLocalHost(), 4001); 
     int port 
      =Integer.parseInt 
       (new BufferedReader 
        (new InputStreamReader(init.getInputStream())).readLine()); 
     init.close(); 
     Socket socket=new Socket(InetAddress.getLocalHost(), port); 
     out = new PrintWriter(socket.getOutputStream(), true); 
     in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 


    while(true){ 
     try { 
      Thread.sleep(5000); 
      out.println("Give me some data"); 
      if(in.readLine().equals("Have some data")){ 
       System.out.println("Data recieved"); 
      }else{ 
       System.out.println("Data not recieved"); 
      } 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 

    } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 


private void createWindow(){ 
    JFrame frame =new JFrame("This is a button"); 
    Container pane=getContentPane(); 
    JButton button=new JButton("This is a button"); 
    button.addActionListener(this); 
    pane.add(button); 
    frame.setTitle("Messaging"); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.setContentPane(pane); 
    frame.setVisible(true); 
    frame.setSize(400, 350); 
} 

@Override 
public void actionPerformed(ActionEvent e) { 
    System.out.println("Button press"); 
    try { 
     out.println("Button Press"); 
     if(in.readLine().equals("Button acknowledged")){ 
      System.out.println("Button complete"); 
     }else{ 
      System.out.println("Button fail"); 
     } 
    } catch (IOException e1) { 
     e1.printStackTrace(); 
    } 
} 

如果按钮被按下,而服务器获取数据它冲突和错误的响应发送。那么我会如何处理这个问题呢?如果我创建一个单独的套接字来处理自动检查,这是服务器必须处理的线程数量的两倍。有更好的解决方案吗? 请你可以尝试解释,因为这对我来说是一个新的领域。

+0

你的第一个问题是这些变量都不应该是静态的,而那些指向特定客户端的变量应该在'Worker'类中,而不是服务器类中。 – EJP

+0

是的服务器工人类中的变量可能不应该是静态的,但这是因为这是我在5分钟内扔在一起的东西,以提供我的问题的一个例子。 而引用特定客户端的变量不在工作者类中,就我所见,它只是服务器套接字,最初的套接字和线程池。那么哪些不是在那里?但正如我已经说过的那样,这只是一些快速拼凑在一起的代码,试图帮助解决我的问题,所以它不会是完美的。 – Nightfortress

回答

2

你的问题是你有两个线程与套接字,你的主线程和Swing事件处理线程进行交互。这意味着两个线程可以排队两个不同的东西,并且响应可能被错误的线程拾取。获取想要的位置的最简单方法是将所有套接字交互放在一个线程中。

有两种方法可以做到这一点。一个是主线程将定期自动检查排队到Swing事件处理线程。然而,这有点复杂,也可能是错误的,因为实际的Swing线程模型与记录的不同。

另一种做法是让Swing事件处理线程将按钮排列到主线程。在这种情况下,您可以使用适当的同步将按钮排队到主线程。主线程的主循环将检查按钮按下并通过套接字发送并等待正确的响应。

+0

好吧,那么如何将按钮按到主线程?任何建议,以便我可以查找如何使用它们? @Warren露水 – Nightfortress

+0

Nevermind我找到了一个解决方案,https://stackoverflow.com/a/16268778/5521916在你的答案帮助下。 – Nightfortress