androidfilekotlinmessagepackkotlin-android-extensions

File byte error in kotlin. How to transfer correctly?


I want to Transfer file with tcp client to server, but image file has been wrong.

My client code is

import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream
import org.msgpack.core.MessageBufferPacker
import org.msgpack.core.MessagePack
import org.msgpack.core.MessageUnpacker
import java.io.*
import java.net.Socket
import java.util.*

fun main(args: Array<String>) {
    fileClient("localhost",1988,"fruit.jpg")
}

class fileClient (host:String, port:Int, file:String){
    var s : Socket ?= null
    var out = ByteArrayOutputStream()
    var msg : MessageBufferPacker = MessagePack.newDefaultBufferPacker()

    init {
        try {
            s = Socket(host,port)
            sendFile(file)
        }catch (e:Exception){
            e.printStackTrace()
        }
    }

    @Throws(IOException::class)
    fun sendFile(file: String) {
        val dos = DataOutputStream(s!!.getOutputStream())
        val buffer = ByteArray(4096)
        val filebytes = File(file).readBytes()
        var msgdata = ByteOutputStream()

        msg.packString(file)
        msg.packBinaryHeader(filebytes.size)
        msg.writePayload(filebytes)

        msg.close()



        val data = msg.toByteArray()
        val datasize = data.size
        val ins = ByteArrayInputStream(data)
        dos.writeInt(datasize)
        while (ins.read(buffer) > 0) {
            dos.write(buffer)
        }
        dos.close()
    }
}

And my server code is

import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream
import org.msgpack.core.MessagePack
import org.msgpack.core.MessageUnpacker
import java.awt.List
import java.io.*
import java.net.ServerSocket
import java.net.Socket
import java.text.SimpleDateFormat
import java.util.*

fun main(args: Array<String>) {
    var fs = FileServer(1988)
    fs.start()
}

class FileServer(port: Int) : Thread() {

    private var ss: ServerSocket? = null

    var fileRealName : String ?= null

    init {
        try {
            ss = ServerSocket(port)
        } catch (e: IOException) {
            e.printStackTrace()
        }

    }

    override fun run() {
        while (true) {
            try {
                val clientSock = ss!!.accept()
                saveFile(clientSock)
            } catch (e: IOException) {
                e.printStackTrace()
            }

        }
    }

    @Throws(IOException::class)
    private fun saveFile(clientSock: Socket) {
        var msgList = ArrayList<Any>()
        val dis = DataInputStream(clientSock.inputStream)
        val msgdata = ByteOutputStream()
        val buffer = ByteArray(4096)
        var read = 0


        while (true) {
            val datalen = dis.readInt() // data length

            if(datalen!= null && datalen >0){
                var finaldata = ByteArray(datalen)
                var process = 0;
                while (process <= datalen) {
                    read = dis.read(buffer)
                    if (read < 0) {
                        return
                    }
                    msgdata.write(buffer)
                    process += 4096
                }
                println(process.toString() + " "+ datalen.toString())
                var allData = msgdata.toByteArray().slice(0..datalen).toByteArray()
                unpackByte(allData)

            }

        }

        msgdata.close()
        dis.close()
    }

    private fun unpackByte(data:ByteArray){

        var unpacker : MessageUnpacker = MessagePack.newDefaultUnpacker(data)

        var fileName = unpacker.unpackString().toString()

        var filesize = unpacker.unpackBinaryHeader()
        var buffer = ByteArray(filesize)
        unpacker.readPayload(buffer)

        var fos = FileOutputStream(fileName)
        fos.write(buffer)
        fos.close()

        unpacker.close()

    }

}

And a file what I want to transfer is enter image description here

but after transfer, image on server is like this. enter image description here

How can I transfer this file correctly?


Solution

  • I didn't succeeded in reproducing your problem. However I think I've found the bug that may be causing corrupted file transfer.

    In your server code there's an infinite loop that returns immediately out of method leaving the rest of method unreachable. This is the clean-up code that closes connections and streams. Quite possibly the OutputStream was not properly closed and this is the cause of corrupted file write.

    That's how the server code should look like:

    val datalen = dis.readInt() // data length
    
    if (datalen > 0) {
        var finaldata = ByteArray(datalen)
         var process = 0;
         while (process <= datalen) {
            read = dis.read(buffer)
            if (read < 0) {
                break
            }
            msgdata.write(buffer)
            process += 4096
        }
        println(process.toString() + " " + datalen.toString())
        val allData = msgdata.toByteArray().slice(0..datalen).toByteArray()
        unpackByte(allData)
    
    }
    
    msgdata.close()
    dis.close()
    

    while loop is unnecessary. Also you probably should just break the loop, not return from function.

    P.S. Have you considered using IOUtils to handle all the IO read/writes? Half of your code could be replaced with just a few lines of code using this library.