Java(网络):在客户端和服务器之间传递递增的值

时间:2014-08-25 03:37:29

标签: java sockets

我应该有多个客户端连接到localhost,并且在连接客户端之后,他可以按一个添加按钮将值递增1.例如,有两个客户端(A和B)。单击“添加”按钮,值(ctr)增加1(ctr = 1),如果B单击“添加”按钮,则值(ctr)再次增加1(ctr)(ctr = 2)

但我正在努力为一个客户端获得正确的结果,所以我将坚持解决为一个客户端首先获得正确的结果,然后再从多个客户端获得正确的结果。但我确实希望任何人都可以为多个客户提供帮助。

我在网络方面不是很擅长并试图实现这一点,而这里我的逻辑只是一个客户

- 在我的按钮actionListener中,每次按下“添加”按钮,我都会将“添加”消息从客户端发送到服务器。

- 服务器收到消息“add”,并将“ctr”变量递增1;

- 服务器将递增的ctr传递给客户端。

但是,当我在添加按钮上单击3次后,我从代码中获得的输出相当奇怪且不稳定。

我的输出

Starting SomeProcess  
1500476704 <--Incremented value passed back to client from the server, it should return 1
SomeProcess took 4 ms
Starting SomeProcess
1751217765 <--Incremented value passed back to client from the server, it should return 2
SomeProcess took 0 ms
Starting SomeProcess
543387502 <--Incremented value passed back to client from the server, it should return 3
SomeProcess took 0 ms

我的代码

Client.java

import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class Client extends JPanel {
    private JButton addBtn = new JButton("Add");
    private long start = 0;
    private PrintWriter output = null;
    private BufferedReader input = null;
    private Socket socket;

    public Client() {
        setLayout(new FlowLayout());
        add(addBtn);

        try {
            socket = new Socket("localhost",4444);
            output = new PrintWriter(socket.getOutputStream(), true);
            input = new BufferedReader(new InputStreamReader(socket.getInputStream()));

        }catch (IOException exception) {
            System.out.println("Error: " + exception);
        }

        addBtn.addActionListener(new AddBtnListener());
    }

    public class AddBtnListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            Thread t = new Thread(new Runnable() {
                public void run() {

                    System.out.println("Starting SomeProcess");
                    start = System.currentTimeMillis();
                    output.println("add");

                    try {
                        DataInputStream inputInt = new DataInputStream((socket.getInputStream()));    
                        System.out.println(inputInt.readInt());
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    long duration = System.currentTimeMillis() - start;
                    System.out.printf("SomeProcess took %,d ms%n", duration );
                }
            });
            t.start();
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new Client());
                frame.pack();
                frame.getPreferredSize();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }
}

Server.java

import java.awt.EventQueue;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import javax.swing.JFrame;
import javax.swing.JPanel; 
import javax.swing.JTextArea;

@SuppressWarnings("serial")
public class Server extends JPanel {

    private Socket threadSocket;
    private JTextArea textArea = new JTextArea(30,30);

    public Server() {
        add(textArea);
        textArea.setEditable(false);
        Thread t = new Thread(new acceptClient());
        t.start();
    }

    class acceptClient implements Runnable {

        @Override   
        public void run() {
            try {
                ServerSocket sSocket = new ServerSocket(4444);
                textArea.append("Server started at: " + new Date());
                while(true) {
                    Socket socket = sSocket.accept();
                    ClientThread cT = new ClientThread(socket);
                    new Thread(cT).start();

                } 
            } catch(IOException exception) {
                System.out.println("Error: " + exception);
            }
        }
    }

    class ClientThread extends Thread {
        String temp = " ";
        DataOutputStream outputInt = null;
        int ctr = 0;
        PrintWriter output;

        public ClientThread(Socket socket) {
            threadSocket = socket;
        }

        @Override  
        public void run() { 
            while(true) {
                try {
                    output = new PrintWriter(threadSocket.getOutputStream(), true);
                    BufferedReader input = new BufferedReader(new InputStreamReader(threadSocket.getInputStream()));
                    output.println("You have connected at: " + new Date());
                    textArea.append("\nClient connected\n");
                    temp = input.readLine();

                    if(temp.equals("add")) {
                        synchronized(this) {
                            ctr++;
                            textArea.append(Integer.toString(ctr));
                            outputInt.write(ctr);
                        }
                    }

                } catch(IOException exception) {
                    System.out.println("Error: " + exception);
                }
            }
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new Server());
                frame.setLocationRelativeTo(null);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setVisible(true);
                frame.setResizable(false);
            }
        });
    }
}

1 个答案:

答案 0 :(得分:1)

看看你写/读过程...

首先,你的服务器确实......

output = new PrintWriter(threadSocket.getOutputStream(), true);
output.println("You have connected at: " + new Date());
//...
ctr++;
outputInt.write(ctr);

但是你的客户只做...

DataInputStream inputInt = new DataInputStream((socket.getInputStream()));
System.out.println(inputInt.readInt());

...这意味着您实际阅读的内容是来自服务器的"You have connected at: " + new Date()响应。

您需要确保以与撰写相同的顺序阅读内容...

我可能会考虑做的是简化流程...我只是继续使用您已设置的DataOutputStream而不是介绍PrintWriter,而是简单地执行类似的操作...

ctr++;
textArea.append(Integer.toString(ctr));
output.println(ctr);
在服务器内

而不是......

在客户端上,您可以执行

System.out.println(input.readLine());
System.out.println(input.readLine());

将阅读&#34; connect&#34;消息和柜台......

旁注

您的服务器ClientThread有一些与我有关的事情......

  1. 无需在PrintWriter内重新创建BufferedReaderwhile-loop,事实上,output并不真正需要成为类实例可变...
  2. 如果由于某种原因引发Exceptionrun方法永远不会退出,这意味着您可能陷入永无止境的循环
  3. 我&#39;,不确定你真的需要synchronized块,因为ctr是这个线程上下文中的一个实例字段,所以除非有什么东西试图在外部修改它,这个只是额外的开销......但是我暂时不管它......
  4. 相反,我可能想做一些像...这样的事情。

    try (PrintWriter output = new PrintWriter(threadSocket.getOutputStream(), true)) {
        try (BufferedReader input = new BufferedReader(new InputStreamReader(threadSocket.getInputStream()))) {
    
            while (true) {
                output.println("You have connected at: " + new Date());
                textArea.append("\nClient connected\n");
                temp = input.readLine();
    
                if (temp != null) {
    
                    if (temp.equals("add")) {
                        synchronized (this) {
                            ctr++;
                            textArea.append(Integer.toString(ctr));
                            output.println(ctr);
                        }
                    }
    
                }
    
            }
    
        }
    } catch (IOException exp) {
        exp.printStackTrace();
    }
    

    代替。

    虽然我知道你可以使用一个try-with-resource语句,但为了清晰起见,我想将两个流创作分开...