我正在为大学任务实现一个Java客户端 - 服务器应用程序,并且我坚持以下几点:我不得不使用客户端服务器,并且每当数据库中的数据发生更改时也会更新视图。我所做的是每当数据库发生变化时,我都会通过"更改数据来通知所有客户。消息,然后客户端应阅读并理解此消息,以便调用将更新其图形界面的方法。但是,或者我在客户端误读了阅读部分,或者由于某些错误,客户不会阅读“更改数据”和“#34;更改数据"消息,所以此时整个卡住了,视图没有更新。
以下是一些相关代码! 服务器类:
public class FinesPaymentServer implements Runnable {
private Database database;
private UserGateway userGateway;
private FineGateway fineGateway;
private DriverGateway driverGateway;
private Socket connection;
private int ID;
static ArrayList<Socket> clientsConnected;
/**
* Constructor of the class connecting to the database and initializing the socket
* @param database the database used
* @param connection the socket for the server
* @param ID the id
*/
private FinesPaymentServer(Database database, UserGateway userGateway, FineGateway fineGateway, DriverGateway driverGateway, Socket connection, int ID) {
this.connection = connection;
this.userGateway = userGateway;
this.fineGateway = fineGateway;
this.driverGateway = driverGateway;
this.database = database;
this.ID = ID;
}
/**
* Run method of the threads for each socket on the server
*/
public void run() {
try {
while(true)
readFromClient(connection);
} catch (IOException | SQLException e) {
System.out.println(e);
}
}
/**
* Read method from the client
* @param client the client socket from where to read
* @throws IOException
* @throws SQLException
*/
public void readFromClient(Socket client) throws IOException, SQLException {
BufferedInputStream is = new BufferedInputStream(client.getInputStream());
InputStreamReader reader = new InputStreamReader(is);
StringBuffer process = new StringBuffer();
int character;
while((character = reader.read()) != 13) {
process.append((char)character);
}
System.out.println("[SERVER READ]: "+process);
String[] words = process.toString().split("\\s+");
switch (process.charAt(0)) {
case 'a' :
{
int type = database.verifyLogin(words[1], words[2]);
sendMessage(client, ""+type + " ");
break;
}
case 'b' :
{
String rs = userGateway.getUsers();
sendMessage(client, rs);
break;
}
case 'c' :
{
userGateway.createUser(words[1], words[2], words[3]);
notifyClients();
break;
}
case 'd' :
{
userGateway.updateUser(words[1], words[2], words[3]);
notifyClients();
break;
}
case 'e' :
{
userGateway.deleteUser(words[1]);
notifyClients();
break;
}
}
try {
Thread.sleep(1000);
} catch (Exception e){}
String time_stamp = new java.util.Date().toString();
String returnCode = "Single Socket Server responded at " + time_stamp + (char) 13;
sendMessage(client, returnCode);
}
/**
* Method for sending messages from the server to the client
* @param client the client socket where to send the message
* @param message the message itself to be sent
* @throws IOException
*/
private void sendMessage(Socket client, String message) throws IOException {
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(client.getOutputStream()));
writer.write(message);
System.out.println("[SERVER WRITE]: "+message);
writer.flush();
}
public void notifyClients() throws IOException
{
for(Socket s : clientsConnected)
{
sendMessage(s, "CHANGE IN DATA ");
}
}
/**
* @param args the command line arguments
* @throws java.sql.SQLException
*/
public static void main(String[] args) throws SQLException {
Database database = new Database();
UserGateway userGateway = new UserGateway();
FineGateway fineGateway = new FineGateway();
DriverGateway driverGateway = new DriverGateway();
clientsConnected = new ArrayList<>();
// Setting a default port number.
int portNumber = 2015;
int count = 0;
System.out.println("Starting the multiple socket server at port: " + portNumber);
try {
ServerSocket serverSocket = new ServerSocket(portNumber);
System.out.println("Multiple Socket Server Initialized");
//Listen for clients
while(true) {
Socket client = serverSocket.accept();
clientsConnected.add(client);
Runnable runnable = new FinesPaymentServer(database, userGateway, fineGateway, driverGateway, client, ++count);
Thread thread = new Thread(runnable);
thread.start();
}
} catch (Exception e) {}
}
}
客户端类:
public class FinesPaymentClient implements Runnable {
private String hostname = "localhost";
private int port = 2015;
Socket socketClient;
AdministratorModel adminModel;
PoliceModel policeModel;
PostModel postModel;
/**
* Constructor of the class
* @param hostname the host name of the connection
* @param port the port of the connection
* @throws UnknownHostException
* @throws IOException
*/
public FinesPaymentClient(String hostname, int port, AdministratorModel adminModel, PoliceModel policeModel, PostModel postModel) throws UnknownHostException, IOException
{
this.hostname = hostname;
this.port = port;
this.adminModel = adminModel;
this.policeModel = policeModel;
this.postModel = postModel;
connect();
}
/**
* Method for connecting to the host by a socket
* @throws UnknownHostException
* @throws IOException
*/
public void connect() throws UnknownHostException, IOException {
System.out.println("Attempting to connect to " + hostname + ":" + port);
socketClient = new Socket(hostname, port);
System.out.println("Connection Established");
}
/**
* Method for reading response from the server
* @return the string read from the server
* @throws IOException
*/
public String readResponse() throws IOException {
String userInput;
BufferedReader stdIn = new BufferedReader(
new InputStreamReader(socketClient.getInputStream()));
System.out.println("[CLIENT READ]:");
while ((userInput = stdIn.readLine()) != null) {
System.out.println(userInput);
return userInput;
}
return userInput;
}
/**
* Method for closing connection between client and server
* @throws IOException
*/
public void closeConnection() throws IOException {
socketClient.close();
}
/**
* Method for writing messages to the server
* @param message the message to be sent
* @throws IOException
*/
public void writeMessage(String message) throws IOException {
String time_stamp = new java.util.Date().toString();
// Please note that we placed a char(13) at the end of process...
// we use this to let the server know we are at the end
// of the data we are sending
String process = message + (char) 13;
BufferedWriter stdOut = new BufferedWriter(
new OutputStreamWriter(socketClient.getOutputStream()));
stdOut.write(process);
System.out.println("[CLIENT WRITE]: "+process);
// We need to flush the buffer to ensure that the data will be written
// across the socket in a timely manner
stdOut.flush();
}
@Override
public void run() {
try {
String response;
while(true)
{
response = readResponse();
System.out.println("HERE"+response.substring(0, 13));
if(response.substring(0, 13).equals("CHANGE IN DATA"))
{
adminModel.setChange();
}
}
} catch (IOException e) {
System.out.println(e);
}
}
/**
* Main method of the application
* @param arg the parameters given as arguments
* @throws SQLException
* @throws UnknownHostException
* @throws IOException
*/
public static void main(String arg[]) throws SQLException, UnknownHostException, IOException {
AdministratorModel adminModel = new AdministratorModel();
PoliceModel policeModel = new PoliceModel();
PostModel postModel = new PostModel();
FinesPaymentClient client = new FinesPaymentClient("localhost", 2015, adminModel, policeModel, postModel);
Runnable client2 = new FinesPaymentClient("localhost", 2015, adminModel, policeModel, postModel);
Thread thread = new Thread(client2);
thread.start();
Login login = new Login();
ClientSide clientSide = new ClientSide(login, client, adminModel, policeModel, postModel);
}
}
ClientSide类:
public class ClientSide {
private final Login login;
private FinesPaymentClient client;
AdministratorModel adminModel;
PoliceModel policeModel;
PostModel postModel;
/**
* Constructor instantiating needed classes
* @param login an instance of the login class
* @param client the client needing the control logic
* @param adminModel
* @param policeModel
* @param postModel
* @throws SQLException using classes connecting to a database sql exceptions can occur
*/
public ClientSide(Login login, FinesPaymentClient client, AdministratorModel adminModel, PoliceModel policeModel, PostModel postModel) throws SQLException
{
this.login = login;
this.client = client;
this.adminModel = adminModel;
this.policeModel = policeModel;
this.postModel = postModel;
login.addButtonListener(new ButtonListener());
}
/**
* Listener for the login button. Reads, verifies and provides the interface according to logged in user type.
*/
class ButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
try
{
client.writeMessage("a " + login.field1.getText()+ " " + login.field2.getText());
String response = client.readResponse();
if(response.charAt(0) == '1')
{
login.setVisible(false);
AdministratorGUI administratorGUI = new AdministratorGUI(adminModel, client);
AdministratorController adminController = new AdministratorController(client, administratorGUI, adminModel);
}
//if user is post office employee
else if(response.charAt(0) == '2')
{
login.setVisible(false);
PostGUI postGUI = new PostGUI();
PostController postController = new PostController(client, postGUI, postModel);
}
//if user is police employee
else if(response.charAt(0) == '3')
{
login.setVisible(false);
PoliceGUI policeGUI = new PoliceGUI();
PoliceController policeController = new PoliceController(client, policeGUI, policeModel);
}
else
{
JOptionPane.showMessageDialog(null,"Login failed! Please try again!");
}
}
catch (IOException ex)
{
Logger.getLogger(ClientSide.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
我99%确定错误是在客户端读取从服务器发送的消息作为通知,但我根本无法弄清楚如何检索该消息。现在我尝试使用客户端线程运行方法,但不起作用。其他类和其他功能工作得很好,这是我唯一的问题。你有什么想法可能是错误吗?我将不胜感激任何帮助。