简体   繁体   English

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

[英]Java(Networking):passing incremented values between client and server

I am supposed to have multiple clients connected to localhost and after the client is being connected, he can press a add button to increment a value by 1. Let take for example there are 2 clients (A and B). 我应该有多个连接到本地主机的客户端,并且在连接客户端后,他可以按添加按钮以将值增加1。以2个客户端(A和B)为例。 A clicks on Add button, The value(ctr) is incremented by 1(ctr=1) and if B clicks on Add Button, the value(ctr) is incremented by 1(ctr) again(ctr =2) A单击添加按钮,值(ctr)增加1(ctr = 1),如果B单击添加按钮,则值(ctr)再次增加1(ctr)(ctr = 2)

But I am struggling to get the correnct results for just one client so I will just stick to solving getting the correct results for one client first before moving on to getting correct results from multiple clients. 但是我一直在努力只为一个客户获得正确的结果,因此我将坚持首先解决一个客户的正确结果,然后再从多个客户那里获得正确的结果。 But I do wish that anyone could provide me help on the multiple clients part as well. 但我确实希望任何人都可以在多个客户方面为我提供帮助。

I am not very good in networking and tried to implement this and here my logic for just ONE client 我的网络能力不是很好,因此尝试实现此功能,这里我仅针对一个客户端的逻辑

-In my button actionListener, Each time the Add button is pressed, I will send the message "add" from the client to the server. -在我的按钮actionListener中,每当按下添加按钮时,我都会将消息“添加”从客户端发送到服务器。

-The server receives the message "add" and will increment the "ctr" variable by 1; -服务器收到消息“ add”,并将“ ctr”变量加1;

-The server will pass the incremented ctr to the client. -服务器会将增加的点击率传递给客户端。

But the output I got from my codes is rather wierd and unstable after I clicked 3 times on the Add Button. 但是,当我在“添加”按钮上单击3次后,我从代码中获得的输出相当不稳定,而且不稳定。

My Output 我的输出

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

My codes 我的密码

Client.java 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 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);
            }
        });
    }
}

Take a look at you write/read process... 看一下您的读写过程...

First, you server does... 首先,您的服务器可以...

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

But your client only does... 但是您的客户只会...

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

...This means what you have actually read is the "You have connected at: " + new Date() response from the server. ...这意味着您实际读到的是服务器的"You have connected at: " + new Date()响应。

You need to make sure you are reading the content in the same order your are writing it... 您需要确保以与编写内容相同的顺序阅读内容...

What I might consider doing is simplifying the process...Instead of introducing the DataOutputStream , I would simply continue to use the PrintWriter you've already set up and simple do something like... 我可能会考虑简化流程...与其介绍DataOutputStream而不是引入DataOutputStreamDataOutputStream继续使用已经设置的PrintWriter ,然后简单地执行以下操作...

ctr++;
textArea.append(Integer.toString(ctr));
output.println(ctr);

within the server instead... 在服务器内...

On the client, you could then do 在客户端上,您可以这样做

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

Which will read the "connect" message and the counter... 它将读取“连接”消息和计数器...

Side notes 旁注

There are a few things about your server ClientThread which concern me... 关于服务器ClientThread的几件事与我有关...

  1. There is no need to re-create the PrintWriter and BufferedReader within the while-loop , in fact, output doesn't really need to be class instance variable... 无需在while-loop内重新创建PrintWriterBufferedReader ,实际上, output实际上不必是类实例变量。
  2. If, for some reason, an Exception is raised, the run method will never exit, this means you could be caught in a never ending loop 如果由于某种原因引发了Exception ,则run方法将永远不会退出,这意味着您可能会陷入永无止境的循环中
  3. I', not sure you really need the synchronized block as ctr is an instance field within the context of this thread, so unless something is going to try and alter it externally, this is just additional overhead...but I'll leave it alone for the moment... 我不确定您是否真的需要synchronized块,因为ctr是此线程上下文中的一个实例字段,因此,除非要在外部尝试对其进行更改,否则这只是额外的开销...但是我将保留它暂时一个人...

Instead, I might be tempted to do something like... 相反,我可能很想做类似...

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

instead. 代替。

While I know you can use a single try-with-resource statement, I wanted to separate the two stream creations for clarity... 虽然我知道您可以使用一个try-with-resource语句,但为了清晰起见,我想将两个流创建分开...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM