我应该有多个客户端连接到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);
}
});
}
}
答案 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
有一些与我有关的事情......
PrintWriter
内重新创建BufferedReader
和while-loop
,事实上,output
并不真正需要成为类实例可变... Exception
,run
方法永远不会退出,这意味着您可能陷入永无止境的循环synchronized
块,因为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
语句,但为了清晰起见,我想将两个流创作分开...