Java使用客户端套接字的多个线程

时间:2017-09-06 21:24:58

标签: java multithreading swing sockets

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

    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();
    }
}

如果在服务器获取数据时按下该按钮,则会发生冲突并发送错误的响应。那我该如何处理呢?如果我创建一个单独的套接字来处理自动检查,那么服务器必须处理的线程数量增加一倍。有更好的解决方案吗? 请你试着解释,因为这对我来说是个新领域。

1 个答案:

答案 0 :(得分:2)

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

有两种方法可以做到这一点。一个是主线程将定期自动检查排队到Swing事件处理线程。然而,由于实际的Swing线程模型与所记录的内容不同,这有点复杂并且可能也有问题。

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