java.net.SocketException:Socket是闭合的OOP设计错误
我正在写一个关于银行系统的服务器-客户端通信的大学项目。其中一个要求是应用程序的OOP设计 我在实现通信方法的类中有一个bug 这是一个客户端代码。服务器端的实现类似,并产生相同的错误 错误的结果是java.net.SocketException:Socket是闭合的OOP设计错误,java,sockets,oop,Java,Sockets,Oop,我正在写一个关于银行系统的服务器-客户端通信的大学项目。其中一个要求是应用程序的OOP设计 我在实现通信方法的类中有一个bug 这是一个客户端代码。服务器端的实现类似,并产生相同的错误 错误的结果是java.net.SocketException:Socket已关闭 实现通信方法的类: import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import ja
java.net.SocketException:Socket已关闭
实现通信方法的类:
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;
}
}
这是调用方法并返回调用的方法的标准类返回:
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);
}
}
使用驱动程序对象调用方法的类:
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);
}
}
我试图缩小代码范围并隔离问题。
类公共类UserInterface
在运行应用程序的线程的run方法中进一步实例化
我是对OOP设计做得太过分了,还是缺少了一些套接字编程概念
如果你不明白,请提问!
建议如何在总体上做得更好!
谢谢大家! 关闭输入或输出流应关闭套接字。在sendMessage中,关闭ObjectOutputStream,这可能反过来关闭传递到构造函数中的底层输出流。cls打开套接字的输入或输出流将关闭套接字
您不应该为每条消息创建新的
ObjectOutputStream
,也不应该在发送一条消息后关闭它。接收时,ObjectInputStream
也是如此。在插座的使用寿命中使用相同的插座。哇,这一点都没想到!谢谢你的回答。:)嘿我遇到了另一个我想不出来的问题。如何打开流进行输入/输出?我尝试定义了两个新方法“public void openStreams(Socket-Socket);”为当前会话和“publicsocketgetsocket();”创建in/out实例的返回接口中当前会话的套接字并实现它们。然后在用户界面中调用一个接一个的连接方法。但是什么也没发生!创建in/out的方法永远不会返回,也不会产生错误!您必须在两端的ObjectInputStream
之前创建ObjectOutputStream
。实际上,您不需要其他方法:只需在创建套接字的同一位置执行即可。在服务器中,您应该在线程的run()
方法的头部执行此操作,该线程创建用于处理每个已接受的Socket
。我现在尝试用不同的方法打开每个流。外流正在开放。在流中打开会冻结程序和方法,永远不会结束。关于它没有“应该”或“可能”:这正是发生的事情。