我正在创建一个多客户聊天服务器程序。消息作为消息对象发送。但是,ServerClient类没有收到消息,我不知道为什么。
客户:
package client;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.*;
import constraints.Constraints;
import message.Message;
import tools.Tools;
import window.ApplicationWindow;
@SuppressWarnings("serial")
public class Client extends ApplicationWindow {
private static final int portNumber = 4444;
private boolean send = false;
private String userName;
private String serverHost;
private int serverPort;
private GridBagLayout layout;
private JTextArea textArea;
private Constraints c_textArea;
private JTextField textField;
private Constraints c_textField;
public static void main(String[] args){
String readName = System.getProperty("user.name");
Client client = new Client(readName, portNumber);
client.startClient();
}
private Client(String userName, int portNumber){
super("ChatApp");
Tools.setLookAndFeel();
this.userName = userName;
this.serverPort = portNumber;
try {
this.serverHost = InetAddress.getLocalHost().getHostAddress();
}catch(Exception e) {
}
layout = new GridBagLayout();
setLayout(layout);
textArea = new JTextArea();
textArea.setColumns(75);
textArea.setRows(20);
c_textArea = new Constraints(0,1);
textArea.setLineWrap(true);
textArea.setEditable(false);
textArea.setVisible(true);
JScrollPane scroll = new JScrollPane (textArea);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
add(scroll, c_textArea);
textField = new JTextField();
textField.setColumns(50);
textField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
send = true;
}
});
c_textField = new Constraints(0,2);
add(textField, c_textField);
pack();
setVisible(true);
setResizable(false);
}
public void output(String message) {
this.textArea.setText(this.textArea.getText() + "\n" + message);
}
private void startClient() {
try{
Socket socket = new Socket(serverHost, serverPort);
Thread.sleep(1000);
ServerThread serverThread = new ServerThread(socket, userName, this);
Thread serverAccessThread = new Thread(serverThread);
serverAccessThread.start();
while(serverAccessThread.isAlive() && this.isRunning()) {
if (send) {
Message message = new Message(textField.getText(), "[" + "]", this.userName);
serverThread.addNextMessage(message);
send = false;
textField.setText("");
}
Thread.sleep(200);
}
}catch(IOException ex){
output("Could not connect to server!");
}catch(InterruptedException ex){
output("Connection interrupted!");
}
}
public void setHost(String serverHost) {
this.serverHost = serverHost;
}
}
ServerClient:
package server;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketException;
import java.util.Scanner;
import message.Message;
public class ServerClient implements Runnable {
private Socket socket;
private PrintWriter clientOut;
private ChatServer server;
private boolean running;
public ServerClient(ChatServer server, Socket socket) {
this.server = server;
this.socket = socket;
this.running = true;
}
private PrintWriter getWriter(){
return clientOut;
}
public boolean isRunning() {
return this.running;
}
public void stop() {
this.running = false;
}
@Override
public void run() {
try{
this.clientOut = new PrintWriter(socket.getOutputStream(), false);
clientOut.flush();
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
while(!socket.isClosed()){
try {
if (in.available() > 0) {
Object i = in.readObject();
if (!i.equals(null)) {
Message input = (Message) i;
String message = input.getText();
String time = input.getTimestamp();
String user = input.getUser();
for(ServerClient thatClient : server.getClients()){
PrintWriter thatClientOut = thatClient.getWriter();
if(thatClientOut != null){
thatClientOut.write(time + " " + user + ": " + message + "\r\n");
thatClientOut.flush();
}
}
}
}
} catch (ClassNotFoundException e) {
System.out.println(e);
} catch (SocketException ex) {
System.out.println(ex);
break;
}
}
in.close();
this.stop();
} catch (IOException e) {
e.printStackTrace();
}
}
//public void fileWrite()
}
ChatServer:
package server;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
//import javax.swing.JComboBox;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import constraints.Constraints;
import tools.Tools;
import window.ApplicationWindow;
import message.Message;
@SuppressWarnings("serial")
public class ChatServer extends ApplicationWindow {
private static final int portNumber = 4444;
private ArrayList<Command> commands;
private int serverPort;
private String serverHost;
private List<ServerClient> clients;
ServerSocket serverSocket;
private GridBagLayout layout;
private JTextArea textArea;
private Constraints c_textArea;
private JTextField textField;
private Constraints c_textField;
public static void main(String[] args){
ChatServer server = new ChatServer(portNumber);
server.startServer();
}
public ChatServer(int portNumber){
super("Server " + portNumber);
this.serverPort = portNumber;
try {
this.serverHost = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
this.serverHost = "";
}
Tools.setLookAndFeel();
initActions();
layout = new GridBagLayout();
setLayout(layout);
textArea = new JTextArea();
textArea.setColumns(75);
textArea.setRows(20);
c_textArea = new Constraints(0,1);
textArea.setLineWrap(true);
textArea.setEditable(false);
textArea.setVisible(true);
JScrollPane scroll = new JScrollPane (textArea);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
add(scroll, c_textArea);
textField = new JTextField();
textField.setColumns(50);
textField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
process(textField.getText());
}
});
c_textField = new Constraints(0,2);
add(textField, c_textField);
pack();
setVisible(true);
setResizable(false);
}
public List<ServerClient> getClients(){
return clients;
}
private void startServer(){
clients = new ArrayList<ServerClient>();
serverSocket = null;
try {
InetAddress addr = InetAddress.getByName(this.serverHost);
serverSocket = new ServerSocket(serverPort, 50, addr);
acceptClients(serverSocket);
} catch (IOException e){
output("[ERROR] COULD NOT LISTEN ON PORT: " + serverPort);
this.stop();
}
}
private void acceptClients(ServerSocket serverSocket){
output("[BEGIN] SERVER STARTING ON PORT: " + serverSocket.getLocalSocketAddress());
while (this.isRunning()) {
try{
Socket socket = serverSocket.accept();
output("[ACCEPT] ACCEPTED CLIENT AT: " + socket.getRemoteSocketAddress());
ServerClient client = new ServerClient(this, socket);
Thread thread = new Thread(client);
thread.start();
clients.add(client);
} catch (IOException ex) {
output("[ERROR] ACCEPT FAILED ON: " + serverPort);
}
}
}
private void initActions() {
this.commands = new ArrayList<Command>();
this.commands.add(new Command() {
public void run() {
output("[COMMAND] IP: " + serverSocket.getInetAddress().toString());
}
public String getTrigger() {
return "-ip";
}
});
this.commands.add(new Command() {
public void run() {
for (ServerClient client : clients) {
if (!client.isRunning()) {
clients.remove(client);
}
}
output("[COMMAND] CLIENTS: " + clients.size());
}
public String getTrigger() {
return "-clients";
}
});
}
public boolean process(String command) {
for (Command c : this.commands) {
if (c.getTrigger().equals(command)) {
c.run();
textField.setText("");
return true;
}
}
return false;
}
public void output(String message) {
this.textArea.setText(this.textArea.getText() + "\n" + message);
}
}
ServerThread:
package client;
import java.io.*;
import java.net.Socket;
import java.util.LinkedList;
import java.util.Scanner;
import message.Message;
@SuppressWarnings("unused")
public class ServerThread implements Runnable {
private Socket socket;
private String userName;
private boolean isAlived;
private final LinkedList<Message> messagesToSend;
private boolean hasMessages = false;
private Client client;
public ServerThread(Socket socket, String userName, Client client){
this.socket = socket;
this.userName = userName;
this.client = client;
messagesToSend = new LinkedList<Message>();
}
public void addNextMessage(Message message) {
synchronized (messagesToSend) {
hasMessages = true;
messagesToSend.push(message);
}
}
@Override
public void run(){
print("Welcome :" + userName);
print("Local Port :" + socket.getLocalPort());
print("Server = " + socket.getRemoteSocketAddress() + ":" + socket.getPort());
try {
ObjectOutputStream serverOut = new ObjectOutputStream(socket.getOutputStream());
serverOut.flush();
ObjectInputStream serverIn = new ObjectInputStream(socket.getInputStream());
while(!socket.isClosed()){
if (serverIn.available() > 0) {
try {
if (serverIn.readObject() != null) {
Message input = (Message) serverIn.readObject();
}
} catch (ClassNotFoundException e) {
System.out.println(e);
}
}
if(hasMessages){
Message nextSend;
synchronized(messagesToSend){
nextSend = messagesToSend.pop();
hasMessages = !messagesToSend.isEmpty();
}
serverOut.writeObject(nextSend);
serverOut.flush();
}
}
serverOut.close();
serverIn.close();
} catch(Exception ex){
ex.printStackTrace();
}
}
public void print(String message) {
this.client.output(message);
}
}
我知道客户端能够连接到服务器,并且两者都可以获取消息并成功调用writeObject()方法。但是,消息永远不会被收到。有人能帮助我吗?
答案 0 :(得分:0)
while(!socket.isClosed()){
if (serverIn.available() > 0) {
try {
if (serverIn.readObject() != null) {
Message input = (Message) serverIn.readObject();
}
} catch (ClassNotFoundException e) {
System.out.println(e);
}
}
if(hasMessages){
Message nextSend;
synchronized(messagesToSend){
nextSend = messagesToSend.pop();
hasMessages = !messagesToSend.isEmpty();
}
serverOut.writeObject(nextSend);
serverOut.flush();
}
}
这都是胡说八道。
isClosed()
返回true。不是在对等设备断开连接时。available()
并且只是在假的情况下旋转循环只是浪费时间。ObjectInputStream.readObect()
仅在您发送空值时返回null。应该更像这样:
for (;;) {
try {
Message input = (Message) serverIn.readObject();
// process input here
} catch (EOFException e) {
break;
} catch (ClassNotFoundException e) {
System.out.println(e);
}
}
if(hasMessages){
Message nextSend;
synchronized(messagesToSend){
nextSend = messagesToSend.pop();
hasMessages = !messagesToSend.isEmpty();
}
serverOut.writeObject(nextSend);
serverOut.flush();
}
}
您应该将其拆分为阅读线程和写作线程,因为writeObject()
和flush()
也可以阻止。相同的评论适用于您使用isClosed()
,available()
,测试null等的其他地方。
hasMessages
标志也不起作用。即使随后添加了消息,它仍将是假的。最好删除它,只需依赖同步块内的messagesToSend.isEmpty()
:
synchronized(messagesToSend){
while (!messagesToSend.isEmpty()){
Message nextSend = messagesToSend.pop();
serverOut.writeObject(nextSend);
}
}
serverOut.flush();