我的代码遇到了一个主要问题,即涉及使用ArrayList来处理连接到服务器的套接字。发生的事情是,一旦客户端向服务器发送消息,服务器就不应该将消息回送给所有客户端。相反,没有任何事情发生。
正常工作的一点是,当客户端加入服务器时,服务器会打印到已连接的客户端输出流,但只要客户端向服务器发送消息,就不会发生任何事情。
以下是Server.class的源代码:
import java.awt.BorderLayout;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class Server {
private JFrame frame;
private JTextArea textArea;
private JScrollPane scrollPane;
private ServerSocket serverSocket;
private Thread inputThread;
private Thread acceptThread;
private ArrayList<Socket> socketList = new ArrayList<>();
private final String TITLE = "Server";
private final int WIDTH = 400;
private final int HEIGHT = 300;
private final int PORT = 9999;
private Server() {
createGUI();
acceptConnections();
startInput();
}
private void acceptConnections() {
try {
serverSocket = new ServerSocket(PORT);
} catch (IOException e1) {
e1.printStackTrace();
}
acceptThread = new Thread(new Runnable() {
public void run() {
while (true) {
try {
Socket socket = serverSocket.accept();
socketList.add(socket);
output("Client " + socket.getInetAddress() + " has joined the server.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
acceptThread.start();
}
private void startInput() {
inputThread = new Thread(new Runnable() {
public void run() {
while (true) {
if (!socketList.isEmpty()) {
for (int i = 0; i < socketList.size(); i++) {
Socket socket = socketList.get(i);
BufferedReader input;
try {
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String message;
while ((message = input.readLine()) != null) {
print(message);
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
});
inputThread.start();
print("Started server successfully.");
}
// private String generateID() {
// StringBuilder id = new StringBuilder();
// Random random = new Random();
// for (int i = 0; i < 6; i++) {
// id.append(random.nextInt(10));
// }
// return id.toString();
// }
private void createGUI() {
textArea = new JTextArea();
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
textArea.setEditable(false);
scrollPane = new JScrollPane(textArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
frame = new JFrame(TITLE);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(WIDTH, HEIGHT);
frame.setLayout(new BorderLayout());
frame.add(scrollPane, BorderLayout.CENTER);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void output(String message) {
print(message);
for (int i = 0; i < socketList.size(); i++) {
Socket socket = socketList.get(i);
try {
PrintStream output = new PrintStream(socket.getOutputStream());
output.println(message);
output.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void print(String message) {
textArea.append(message + "\n");
}
public static void main(String[] args) {
new Server();
}
}
以下是连接到服务器的Client.class的源代码:
import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class Client implements KeyListener {
private JFrame frame;
private JTextArea textArea;
private JScrollPane scrollPane;
private JTextField textField;
private Socket socket;
private BufferedReader input;
private PrintStream output;
private Thread inputThread;
private final String TITLE = "Client";
private final int WIDTH = 600;
private final int HEIGHT = 500;
private final String IP = "localhost";
private final int PORT = 9999;
private Client() {
createGUI();
connect(1);
startThread();
}
private void connect(int attempt) {
print("Attempting to connect to server... Attempt #" + attempt);
try {
socket = new Socket(IP, PORT);
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
output = new PrintStream(socket.getOutputStream());
} catch (IOException e) {
attempt++;
connect(attempt);
}
}
private void startThread() {
inputThread = new Thread(new Runnable() {
public void run() {
String message;
try {
while ((message = input.readLine()) != null) {
print(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
inputThread.start();
}
private void createGUI() {
textArea = new JTextArea();
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
textArea.setEditable(false);
scrollPane = new JScrollPane(textArea);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
textField = new JTextField();
textField.addKeyListener(this);
frame = new JFrame(TITLE);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(WIDTH, HEIGHT);
frame.setLayout(new BorderLayout());
frame.add(scrollPane, BorderLayout.CENTER);
frame.add(textField, BorderLayout.SOUTH);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private void send(String message) {
output.println(message);
output.flush();
textField.setText(null);
}
private void print(String message) {
textArea.append(message + "\n");
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
send(textField.getText());
}
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
public static void main(String[] args) {
new Client();
}
}
您可以轻松地将此代码复制并粘贴到您自己的工作区中,因为它不需要任何其他内容。
答案 0 :(得分:0)
PrintWriter
已缓冲。如果您希望立即阅读,则需要在每条消息后flush()
。
您的读取循环不正确:
public void run() {
while (true) {
try {
if (input.ready()) {
String message = input.readLine();
print(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
更改为:
public void run() {
String message;
try {
while ((message = input.readLine()) != null) {
print(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
目前你在没有输入的情况下吸烟,如果有IOException.
<和,则和 / p>
每个客户端需要一个线程。这种使用单个线程从套接字数组中读取的技术是行不通的。
答案 1 :(得分:0)
&#34;请注意,此实现未同步。如果多个线程同时访问ArrayList实例,并且至少有一个线程在结构上修改了列表,则必须在外部进行同步。&#34;
这解决了我的问题!我想,但是我从ArrayList文档中得到了它。谢谢你的帮助。