'DataInputStream.readInt() returns EOFException when connection is made immediately and no data has been transferred
I'm implementing a 2-way file transfer between the server (Java FX) application and the client (A mobile application). File transfer from the JavaFX to the mobile app is successful, however when I tried to send files from the mobile app to the JavaFX application, I get an EOFException immediately I connect even when no files have been sent from the mobile app.
However, whenever I commented out the function used for receiving files from the JavaFX application, no error is thrown. I don't know, but it seems both inputStreams and outputStreams of both applications seem to clash or maybe there's something I am missing. I have googled this error all to no avail.
Minimal reproducible example of Server Code:
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
public class Server {
DataOutputStream dataOutputStream;
DataInputStream dataInputStream;
public Server(){
try{
int port = 19051;
ServerSocket serverSocket = new ServerSocket(port);
while (true){
Socket socket = serverSocket.accept();
dataInputStream = new DataInputStream(socket.getInputStream());
dataOutputStream = new DataOutputStream(socket.getOutputStream());
MyThread myThread = new MyThread();
new Thread(myThread).start();
}
}
catch (IOException exception){
exception.printStackTrace();
}
}
class MyThread implements Runnable{
@Override
public void run() {
receiveFilesFromClient();
}
}
public void receiveFilesFromClient(){
try {
int fileCount = dataInputStream.readInt();
for (int i = 0; i < fileCount; ++i) {
String filename;
byte[] fileContentBytes;
int fileNameLength = dataInputStream.readInt();
if (fileNameLength > 0) {
byte[] fileNameBytes = new byte[fileNameLength];
dataInputStream.readFully(fileNameBytes, 0, fileNameLength);
filename = new String(fileNameBytes, StandardCharsets.UTF_8);
int fileContentLength = dataInputStream.readInt();
if (fileContentLength > 0) {
fileContentBytes = new byte[fileContentLength];
dataInputStream.readFully(fileContentBytes, 0, fileContentBytes.length);
}
}
}
}
catch (IOException exception){
exception.printStackTrace();
}
}
}
Minimal reproducible example for the mobile app:
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.os.StrictMode
import android.provider.OpenableColumns
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.widget.Button
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import java.io.*
import java.net.InetSocketAddress
import java.net.Socket
private const val REQUEST_EXTERNAL_STORAGE = 1
private const val CHOOSE_FILES = 1000
private const val TAG = "SendReceiveFileActivity"
class SendReceiveFileActivity : AppCompatActivity() {
private var ip: String? = null
private var port: Int? = null
var clientSocket: Socket? = null
private lateinit var myThread: MyThread
private lateinit var sendButton: Button
private var dataInputStream: DataInputStream? = null
private var dataOutputStream: DataOutputStream? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_send_receive_file)
val policy = StrictMode.ThreadPolicy.Builder().permitAll().build()
StrictMode.setThreadPolicy(policy)
ip = intent.getStringExtra("ip")
port = intent.getStringExtra("port")?.toInt()
verifyStoragePermissions(this)
sendButton = findViewById(R.id.btnSend)
sendButton.setOnClickListener {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "*/*"
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
startActivityForResult(Intent.createChooser(intent, "Choose Files"), CHOOSE_FILES)
}
myThread = MyThread()
Thread(myThread).start()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == CHOOSE_FILES) {
if (resultCode == RESULT_OK) {
if (data!!.clipData != null) {
val count = data.clipData!!.itemCount
var currentItem = 0
dataOutputStream?.writeInt(count)
while (currentItem < count) {
val uri = data.clipData!!.getItemAt(currentItem).uri
val fileInfo = getDataFromUri(uri)
sendFiles(uri, fileInfo)
currentItem += 1
}
}
else if (data.data != null) {
val uri = data.data!!
val fileInfo = getDataFromUri(uri)
sendFiles(uri, fileInfo)
}
}
}
}
private fun getDataFromUri(uri: Uri): Pair<String, Long>{
val cursor = contentResolver.query(uri, null, null,
null, null)
val nameIndex = cursor?.getColumnIndex(OpenableColumns.DISPLAY_NAME)!!
val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)
cursor.moveToFirst()
val name = cursor.getString(nameIndex)
val size = cursor.getLong(sizeIndex)
cursor.close()
return Pair(name, size)
}
private fun sendFiles(uri: Uri, fileInfo: Pair<String, Long>){
try {
val inputStream = contentResolver.openInputStream(uri)
val fileName = fileInfo.first
Log.d(TAG, "File $fileName sent")
val fileNameBytes = fileName.toByteArray(Charsets.UTF_8)
val fileContentBytes = ByteArray(fileInfo.second.toInt())
inputStream!!.read(fileContentBytes)
dataOutputStream?.writeInt(fileNameBytes.size)
dataOutputStream?.write(fileNameBytes)
dataOutputStream?.writeInt(fileContentBytes.size)
dataOutputStream?.write(fileContentBytes)
dataOutputStream?.flush()
} catch (exception: IOException) {
exception.printStackTrace()
}
}
inner class MyThread: Runnable {
override fun run() {
clientSocket = Socket()
clientSocket?.connect(port?.let { InetSocketAddress(ip, it) }, 5000)
Log.d(TAG, "Socket Connected")
dataInputStream = DataInputStream(clientSocket?.getInputStream())
dataOutputStream = DataOutputStream(clientSocket?.getOutputStream())
while (true){
val fileNameLength = dataInputStream?.readInt()
if (fileNameLength!! > 0){
val fileNameBytes = ByteArray(fileNameLength)
dataInputStream?.readFully(fileNameBytes, 0, fileNameLength)
val filename = String(fileNameBytes)
val fileContentLength = dataInputStream?.readInt()
if (fileContentLength!! > 0){
val fileContent = ByteArray(fileContentLength)
dataInputStream?.readFully(fileContent, 0, fileContentLength)
//downloadFile(filename, fileContent)
}
}
}
}
}
}
The error message which is continually displayed in the logcat because of the loop is this:
java.io.EOFException
at java.base/java.io.DataInputStream.readInt(DataInputStream.java:397)
at com.sirdave.Controller.receiveFileFromClient(Controller.java:208)
at com.sirdave.Controller$MyThread.run(Controller.java:174)
at java.base/java.lang.Thread.run(Thread.java:834)
java.io.EOFException
Solution 1:[1]
Your client is sending only 1 file (but the function name is plural!). Does it disconnect afterward?
The server is looping endlessly to read multiple files (but the function name is singular!).
If the client disconnects after sending, it makes perfect sense why the receiving code would then throw an EOF error.
If you want to leave the connection open, either:
get rid of the reading loop in the server and just read 1 file at a time, to match the client sending 1 file at a time:
server:
public void receiveFileFromClient(){ try { String filename; byte[] fileContentBytes; int fileNameLength = dataInputStream.readInt(); if (fileNameLength > 0) { byte[] fileNameBytes = new byte[fileNameLength]; dataInputStream.readFully(fileNameBytes, 0, fileNameLength); filename = new String(fileNameBytes, StandardCharset.UTF_8); } int fileContentLength = dataInputStream.readInt(); if (fileContentLength > 0) { fileContentBytes = new byte[fileContentLength]; dataInputStream.readFully(fileContentBytes, 0, fileContentBytes.length); } System.out.println("File name received is " + filename); //downloadFile(filename, fileContentBytes); } catch (IOException exception){ exception.printStackTrace(); } }client:
private fun sendFile(uri: Uri, fileInfo: Pair<String, Long>){ try { val inputStream = contentResolver.openInputStream(uri) //val fileInputStream = FileInputStream(file.absolutePath) val fileName = fileInfo.first val fileNameBytes = fileName.toByteArray(Charsets.UTF_8) val fileContentBytes = ByteArray(fileInfo.second.toInt()) //val num: Int = fileInputStream.read(fileContentBytes) inputStream!!.read(fileContentBytes) dataOutputStream?.writeInt(fileNameBytes.size) dataOutputStream?.write(fileNameBytes) dataOutputStream?.writeInt(fileContentBytes.size) dataOutputStream?.write(fileContentBytes) dataOutputStream?.flush() } catch (exception: IOException) { exception.printStackTrace() } }have the client send an integer first indicating the number of files being sent, before then sending their datas, so the server knows when the stop looping:
server:
public void receiveFilesFromClient(){ try { int fileCount = dataInputStream.readInt(); for (int i = 0; i < fileCount; ++i) { String filename; byte[] fileContentBytes; int fileNameLength = dataInputStream.readInt(); if (fileNameLength > 0) { byte[] fileNameBytes = new byte[fileNameLength]; dataInputStream.readFully(fileNameBytes, 0, fileNameLength); filename = new String(fileNameBytes, StandardCharset.UTF_8); } int fileContentLength = dataInputStream.readInt(); if (fileContentLength > 0) { fileContentBytes = new byte[fileContentLength]; dataInputStream.readFully(fileContentBytes, 0, fileContentBytes.length); } System.out.println("File name received is " + filename); //downloadFile(filename, fileContentBytes); } } catch (IOException exception){ exception.printStackTrace(); } }client:
private fun sendFile(uri: Uri, fileInfo: Pair<String, Long>){ try { val inputStream = contentResolver.openInputStream(uri) //val fileInputStream = FileInputStream(file.absolutePath) val fileName = fileInfo.first val fileNameBytes = fileName.toByteArray(Charsets.UTF_8) val fileContentBytes = ByteArray(fileInfo.second.toInt()) //val num: Int = fileInputStream.read(fileContentBytes) inputStream!!.read(fileContentBytes) dataOutputStream?.writeInt(1) dataOutputStream?.writeInt(fileNameBytes.size) dataOutputStream?.write(fileNameBytes) dataOutputStream?.writeInt(fileContentBytes.size) dataOutputStream?.write(fileContentBytes) dataOutputStream?.flush() } catch (exception: IOException) { exception.printStackTrace() } }
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
