2016-08-23 27 views
0

我想用tcp客户端传输文件到服务器,但映像文件出错了。kotlin中的文件字节错误。如何正确传输?

我的客户端代码

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() 
    } 
} 

而我的服务器代码是

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() 

    } 

} 

和文件我想转移是 enter image description here

但转移后,在服务器上的图像是喜欢这个。 enter image description here

如何正确传输此文件?

回答

1

我没有成功地再现您的问题。不过,我认为我发现了可能导致文件传输损坏的错误。

在你的服务器代码中有一个无限循环,它立即返回方法离开剩下的方法不可达。这是关闭连接和流的清理代码。很可能OutputStream没有正确关闭,这是造成文件写入损坏的原因。

这是服务器端的代码应该如何看起来像:

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循环是不必要的。你也许应该只是break循环,而不是return从函数。

P.S. 您是否考虑过使用来处理所有IO读/写操作?你的一半代码可以用这个库的几行代码替换。

+0

谢谢!我删除while循环,它的工作原理! – Icarusud

相关问题