服务器不会将消息回送给客户端

时间:2014-11-20 00:54:04

标签: java arrays sorting arraylist server

我的代码遇到了一个主要问题,即涉及使用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();
}

}

您可以轻松地将此代码复制并粘贴到您自己的工作区中,因为它不需要任何其他内容。

2 个答案:

答案 0 :(得分:0)

  1. PrintWriter已缓冲。如果您希望立即阅读,则需要在每条消息后flush()

  2. 您的读取循环不正确:

    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>

  3. 每个客户端需要一个线程。这种使用单个线程从套接字数组中读取的技术是行不通的。

答案 1 :(得分:0)

&#34;请注意,此实现未同步。如果多个线程同时访问ArrayList实例,并且至少有一个线程在结构上修改了列表,则必须在外部进行同步。&#34;

这解决了我的问题!我想,但是我从ArrayList文档中得到了它。谢谢你的帮助。