Send file with socket BIO use Socket, ServerSocket, ObjectInputStream and ObjectOutputStream but blocked. The detail code is: Model:
@Data
@ToString
public class FileTransModel implements Serializable {
private String fileName;
private Long fileLength;
private Integer status;
}
Client:
public class FileTransClient {
private static final int BUFFER_SIZE = 1024 * 8;
private static final byte[] BUFFER = new byte[BUFFER_SIZE];
public static void main(String[] args) {
try (Socket socket = new Socket("localhost", 1888);
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream())) {
File file = new File("D:\\trans\\1.mp4");
FileTransModel fileTransModel = new FileTransModel();
fileTransModel.setFileName(file.getName());
fileTransModel.setFileLength(file.length());
oos.writeObject(fileTransModel);
FileInputStream fileInputStream = new FileInputStream(file);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
int len;
while ((len = bufferedInputStream.read(BUFFER)) != -1) {
System.out.println(len);
oos.write(BUFFER, 0, len);
oos.flush();
}
System.out.println("file send over");
FileTransModel model = (FileTransModel) ois.readObject();
System.out.println(model);
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
Server:
public class FileTransServer {
private static final int BUFFER_SIZE = 1024 * 8;
private static final byte[] BUFFER = new byte[BUFFER_SIZE];
public static void main(String[] args) {
ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(1888);
System.out.println("Socket Server start on port: 1888");
while(true) {
Socket accept = serverSocket.accept();
System.out.println("new file come!");
new Thread(new Task(accept)).start();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static class Task implements Runnable {
Socket socket;
public Task(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
FileTransModel fileTransModel = (FileTransModel) ois.readObject();
System.out.println(fileTransModel);
File file = new File("D:\\trans_rec2\\"+fileTransModel.getFileName());
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fos);
int len;
len = ois.read(BUFFER);
int size = 0;
while (true) {
size += len;
System.out.println(len + ": " + size);
if (len == -1) {
break;
}
bufferedOutputStream.write(BUFFER, 0, len);
bufferedOutputStream.flush();
len = ois.read(BUFFER);
}
System.out.println("file write over");
fileTransModel.setStatus(0);
oos.writeObject(fileTransModel);
System.out.println("file receive over");
} catch (IOException | ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
}
and the result is : enter image description here Client had trans over, but Server is like that: enter image description here it cannot go on. how to fix it
I have tried to use DataInputStream and DataOutputStream, but the result is the same.
According to the documentation of
readmethod inObjectInputStream:So basically you are never getting
lento be equal to-1at server side. That's because of the sequence of events:ObjectInputStreamis in blocking I/O mode here, so isreadObjectin the following snippet of your client side code:-1(assuming noIOExceptionoccurs) inside the loop, then it is not going to send the model back.As a result both sides are blocked waiting from each other.
To solve this you can signify the end of file transmission in a way such that the server knows when to stop reading file bytes. Since the file contents can be arbitrary and its size is not pre-determined at server side, then you can send the file size before you begin sending its contents to the server. But the model already has this information, so your reading loop in the server side can be modified from:
to:
Closing the client side
ObjectOutputStream(theoosreference) right after writing the file contents, in order for example to get a-1at the server side, is not an option here since closingooswould close the underlyingOutputStreamof theSocket, which in turn according to the documentation would close theSocketitself. So then if you were going to send the model back (ie from server to client), then aSocketExceptionwould be raised (theSocketwould be no more usable).