目前作业有一个问题是说给一个图书管理系统编写使用网络传输+多线程的实现方法来完成序列化文件传输。做法其实跟序列化差不多,这里记一些遇到的错误:
服务端代码
package com.java.Server;
import com.java.DAO.ExpressDAO;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
static int client_num = 0; //当前连接的客户端数量
public static void main(String[] args) throws IOException {
int port_num = 5555; //端口号
final String filePath = "DAO.txt";
ServerSocket serverSocket = new ServerSocket(port_num);
System.out.println("服务器已经启动,端口号为:"+port_num);
//无限循环用于接收新来的client
//这里用do while循环,当客户端使用人数为0的时候就结束服务端
do{
//与客户端连接,建立socket
Socket socket = serverSocket.accept();
client_num++;
System.out.println("当前客户端连接数量为:"+client_num);
new Thread(){
@Override
public void run() {
try{
//先建立socket的输出流,因为socket只实现了这个方法
OutputStream os = socket.getOutputStream();
//因为要写的是序列化的文件,所以这里使用ObjectOutputStream(os)
ObjectOutputStream socket_oos = new ObjectOutputStream(os);
//接下来是序列化标准流程,先用ObjectInputStream读一个file,
// 然后转换file成特定形式的object,然后向客户端写过去这个object
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("DAO.txt"));
ExpressDAO expressDAO = (ExpressDAO) ois.readObject();
socket_oos.writeObject(expressDAO);
//socket_oos.close();
ois.close();
//从客户端那边读过来更新的文件,然后写进DAO.txt
InputStream is = socket.getInputStream();
ObjectInputStream socket_ois = new ObjectInputStream(is);
ExpressDAO express = (ExpressDAO) socket_ois.readObject();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("DAO.txt"));
oos.writeObject(express);
//socket_ois.close();
oos.close();
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
client_num--;
System.out.println("有一个线程退出,目前剩余"+client_num+"线程");
}
}.start();
}while(client_num != 0);
System.out.println("服务器结束");
}
}
在服务器端我注释了两行代码,分别是socket_ois.close();和socket_oos.close();
因为如果不注释掉会出现以下报错
java.net.SocketException: Socket is closed
at java.net.Socket.getInputStream(Socket.java:903)
at com.java.Server.Server$1.run(Server.java:40)
查了一下StackOverflow发现问题其实是因为如果我关闭了不管是socket的输入流还是输出流都会导致整个socket关闭,所以如果后续还有数据传输发生就会出现这种报错。
原文:
A ‘Socket closed’ exception means that the application that caught the exception closed the socket and then kept trying to use it. Please note that closing the input or output stream of a socket closes the other stream and the socket as well. According to your statements seems you close the stream before using the socket to send data.
于是我点进去了ObjectOutputStream.close()的源码看了看,发现源码的意思是调用该方法,任何和他涉及到的相关资源也会关闭。所以说我原来以为我只是想关闭oos,没想到把socket的outputStream也关了。但是也了解了如果我要关闭,我关闭最大的即可。
/**
* Closes the stream. This method must be called to release any resources
* associated with the stream.
*
* @throws IOException If an I/O error has occurred.
*/
public void close() throws IOException {
flush();
clear();
bout.close();
}