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

Java(网络):在客户端和服务器之间传递增量值,java,sockets,Java,Sockets,我应该有多个客户端连接到localhost,在连接客户端之后,他可以按add按钮将值增加1。例如,有两个客户机(A和B)。A单击Add按钮,值(ctr)增加1(ctr=1),如果B单击Add按钮,值(ctr)再次增加1(ctr=2) 但我正努力为一个客户获得正确的结果,所以我将坚持先解决为一个客户获得正确结果的问题,然后再继续从多个客户获得正确结果。但我也希望有人能在多个客户方面为我提供帮助 我不太擅长联网,并尝试实现这一点,这里我的逻辑仅适用于一个客户机 -在ButtonActionListe

我应该有多个客户端连接到localhost,在连接客户端之后,他可以按add按钮将值增加1。例如,有两个客户机(A和B)。A单击Add按钮,值(ctr)增加1(ctr=1),如果B单击Add按钮,值(ctr)再次增加1(ctr=2)

但我正努力为一个客户获得正确的结果,所以我将坚持先解决为一个客户获得正确结果的问题,然后再继续从多个客户获得正确结果。但我也希望有人能在多个客户方面为我提供帮助

我不太擅长联网,并尝试实现这一点,这里我的逻辑仅适用于一个客户机

-在ButtonActionListener中,每次按下Add按钮时,我都会将消息“Add”从客户端发送到服务器

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

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

但是,在我点击了3次Add按钮之后,我从代码中得到的输出非常复杂且不稳定

我的输出

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

看看您的写/读过程

首先,你的服务器

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());
…这意味着您实际读取的是您在以下位置连接的
:“+new Date()
服务器响应

你需要确保阅读内容的顺序与写作顺序相同

我可以考虑的是简化过程……而不是引入<代码> DATAOUTPATSWORDS,我将继续使用<代码> PrimTrriste<代码>您已经设置并简单地做了一些类似的事情…

ctr++;
textArea.append(Integer.toString(ctr));
output.println(ctr);
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();
}
而是在服务器中

在客户机上,您可以这样做

System.out.println(input.readLine());
System.out.println(input.readLine());
将读取“连接”消息和计数器

旁注

关于您的服务器
ClientThread
有几件事与我有关

  • 无需在
    while循环中重新创建
    PrintWriter
    BufferedReader
    ,事实上,
    输出
    实际上不需要是类实例变量
  • 如果出于某种原因引发了
    异常
    ,则
    运行
    方法将永远不会退出,这意味着您可能会陷入一个永无止境的循环
  • 我不确定您是否真的需要
    synchronized
    块,因为
    ctr
    是这个线程上下文中的一个实例字段,所以除非有什么东西试图在外部对其进行更改,否则这只是额外的开销……但我暂时不考虑它
  • 相反,我可能会想做一些像

    ctr++;
    textArea.append(Integer.toString(ctr));
    output.println(ctr);
    
    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
    语句,但为了清晰起见,我想将两个流创建分开…

    感谢您的详细建议。我会考虑这一点