我正在写一个关于服务器 - 客户端通信的银行系统的大学项目。其中一个要求是应用程序的OOP设计。
我在课堂上有一个错误,我正在实现通信方法。
这是客户端代码。服务器端实现类似,并产生相同的错误。
错误的结果是java.net.SocketException: Socket is closed
实现通信方法的类:
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
// My custom interface
public class DriveableImpl implements Driveable{
private Socket socket;
private ObjectOutputStream out;
private ObjectInputStream in;
protected DriveableImpl() {}
// Method that set a socket for a current communication instance
private void setSocket(Socket socket) {
this.socket = socket;
}
// Method to connect to a server that takes parameters required to open socket
@Override
public void connect(String ip, int port){
try {
socket = new Socket(ip, port); // open new socket
setSocket(socket); // set a socket for a current instance to use in other methods
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// Method to close connection with a server
// Oddly, this method is not bugged and can close socket safely
@Override
public void disconnect(){
sendMessage(0); // send a tag number of a method to a server
if(socket != null){
try {
System.out.println("Closing socket: " + socket);
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// Method produce BUG
// Method that accepts any java object as a parameter and send it through a socket of a current instance
@Override
public void sendMessage(Object message) {
try{
out = new ObjectOutputStream(socket.getOutputStream()); // new object stream with a given socket
out.writeObject(message); // send an object stream through a socket
out.flush(); // flush the stream to insure all data is sent and stream is free for new objects
out.close(); // close a stream for current method invocation
}
catch(IOException ioException){
ioException.printStackTrace();
}
}
// Method has a BUG
// Method that reads objects sent by server through a socket
@Override
public Object receiveMessage(){
try{
in = new ObjectInputStream(socket.getInputStream()); // creating new stream to read serialized objects from socket stream
try {
return in.readObject(); // return an object that was read from stream
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally{
in.close(); // close the stream when object is read and returned
}
} catch(IOException ioException){
ioException.printStackTrace();
}
return null; // returns null if something went wrong
}
// Method that produce BUG
// Method that processes user registration
@Override
public void registration(){
sendMessage(2); // send a tag number of a method to a server
try {
String outcome = (String) receiveMessage(); // waiting for response from server
System.out.println(outcome);
} catch (Exception e) {
e.printStackTrace();
}
}
// Method that produce BUG
// Method that processes user login and returns login status as boolean expression
@Override
public boolean login(){
sendMessage(1); // send a tag number of a method to a server
// Block that receives message from a server about login status, i.e., logged in or reasons for not being logged in
try {
outcome = (String) receiveMessage();
System.out.println(outcome);
return (boolean)receiveMessage(); // method returns boolean (true/false) that is required
// to manipulate authentication and issue authorization privileges
} catch (Exception e) {
e.printStackTrace();
} // waiting for response from server
return false; // if something goes wrong, return false
}
} // end of DriveableImpl class
这是调用方法并返回被调用方法返回的标准类:
package ie.gmit.sw.client.methods;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MethodInvoker implements InvocationHandler{
private Object returnObject = null; // object that will hold any returns from invoked methods
private final Driveable userInterface;
protected MethodInvoker(Driveable ui) {
this.userInterface = ui;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException{
System.out.println("BEFORE");
returnObject = method.invoke(userInterface, args);
System.out.println(method.getName());
System.out.println("AFTER");
return returnObject;
}
}
封装MethodInvoker类和实现通信方法的类之间绑定的类:
package ie.gmit.sw.client.methods;
import java.lang.reflect.Proxy;
// Extending a class that implements Driveable Interface
// I thought it's a good use of polymorphism
// Used later to create instance of this class of a type Driveable to maximize abstraction
public class IssueDriver extends DriveableImpl {
private DriveableImpl di = new DriveableImpl(); // creating Object with implemented methods that are required to handle
private MethodInvoker handler = new MethodInvoker(di); // creating Object that handles/executes methods from implementation class
// Creating driver through which methods can be called
private final Driveable driver = (Driveable) Proxy.newProxyInstance(Driveable.class.getClassLoader(),
new Class[] { Driveable.class },
handler);
// Constructor that carries driver object
public IssueDriver() {
getDriver();
}
// returns driver
private Driveable getDriver() {
return driver;
}
}
使用驱动程序对象调用方法的类:
package ie.gmit.sw.client;
import java.util.Scanner;
import ie.gmit.sw.client.methods.Driveable;
import ie.gmit.sw.client.methods.IssueDriver;
public class UserInterface {
private int option;
private Scanner input;
private Driveable driver; // methods driver object
private boolean authenticated = false; // Variable to verify authentication and give corresponding authorization rights.
protected UserInterface() {
driver = new IssueDriver(); // creating new instance of a methods driver i.e., user options in UI
}
protected void menu() {
input = new Scanner(System.in);
try { /* ip port*/
driver.connect("localhost", 2017); // Method that connects to a server. Excepts parameters with ip address and port number.
} catch (Exception connect) {
connect.printStackTrace();
}
do{
if(authenticated == false){
System.out.println("Choose from these choices");
System.out.println("-------------------------\n");
System.out.println("1 - Login");
System.out.println("2 - Register");
System.out.println("0 - Quit");
option = input.nextInt();
switch(option){
case 1: System.out.println("Login");
try {
authenticated = driver.login(); // Method sends an object with user input for login
// and returns status response from the server.
} catch (Exception login) {
// TODO Auto-generated catch block
login.printStackTrace();
}
break;
case 2: System.out.println("Registration");
System.out.println();
try {
driver.registration(); // Method sends an object with registration data to the server.
// Receives status message from server.
} catch (Exception registration) {
// TODO Auto-generated catch block
registration.printStackTrace();
}
break;
case 0: System.out.println("Quit");
try {
driver.disconnect(); // Method closes connection with server.
} catch (Exception discon){
discon.printStackTrace();
}
break;
}
}
else if(authenticated == true){
// ....
}
}while(option != 0);
}
}
我试图缩小代码并隔离问题。
类public class UserInterface
进一步在Thread的run方法中实例化以运行app。
我是否过度使用OOP设计,或者我错过了一些套接字编程概念?
如果您不明白,请提出问题! 建议一般情况下如何做得更好! 谢谢!
答案 0 :(得分:0)
关闭输入或输出流应关闭套接字。在sendMessage中,您关闭ObjectOutputStream,它可能会关闭您传递给构造函数的基础输出流。
答案 1 :(得分:0)
Clloing套接字的输入或输出流会关闭套接字。
您不应为每条消息创建一个新的ObjectOutputStream
,并且在发送消息后不应将其关闭。接收时ObjectInputStream
也是如此。在插座的使用寿命中使用相同的插座。