我应该有多个客户端连接到本地主机,并且在连接客户端后,他可以按添加按钮将值增加 1。例如,有 2 个客户端(A 和 B)。 A点击添加按钮,值(ctr)增加1(ctr=1),如果B点击添加按钮,值(ctr)再次增加1(ctr)(ctr =2)
但我正在努力为一个客户获取正确的结果,因此我将坚持首先解决为一个客户获取正确的结果,然后再继续从多个客户获取正确的结果。但我确实希望任何人都可以在多个客户端方面为我提供帮助。
我不太擅长网络,并尝试实现这一点,这里是我的逻辑一个客户端
-在我的按钮actionListener中,每次按下“添加”按钮时,我都会将消息“add”从客户端发送到服务器。
-服务器收到消息“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
我的代码
客户端.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);
}
});
}
}
服务器.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()
响应。
您需要确保您阅读内容的顺序与编写内容的顺序相同...
我可能会考虑做的是简化流程...我会简单地继续使用您已经设置的 PrintWriter
,而不是引入 DataOutputStream
简单地做一些事情,比如...
ctr++;
textArea.append(Integer.toString(ctr));
output.println(ctr);
在服务器内......
在客户端,您可以这样做
System.out.println(input.readLine());
System.out.println(input.readLine());
它将读取“连接”消息和计数器...
旁注
关于您的服务器ClientThread
,有一些事情让我担心......
- 无需在
while-loop
内重新创建PrintWriter
和BufferedReader
,事实上,output
并不需要是类实例变量... - 如果由于某种原因引发
Exception
,run
方法将永远不会退出,这意味着您可能会陷入永无休止的循环 - 我',不确定您是否真的需要
synchronized
block ,因为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
语句,但为了清楚起见,我想将两个流创建分开......
关于Java(网络):passing incremented values between client and server,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25478695/