Reading socket inputstream hangs the whole program

by wrapping it in Scanner, hasNextLine method gets right output but it stuck at last line
and by using hasNextByte give “[Ljava.lang.Object;@3bd3942” but does not blocks my code
other things i have tried are

and link to code is here

If you look at the implementation of readBytes() you can see that it creates a buffer (that it will return) and passes it to copyTo to do the actual reading. Below is the implementation of copyTo:

public fun InputStream.copyTo(out: OutputStream, bufferSize: Int = DEFAULT_BUFFER_SIZE): Long {
    var bytesCopied: Long = 0
    val buffer = ByteArray(bufferSize)
    var bytes = read(buffer)
    while (bytes >= 0) {
        out.write(buffer, 0, bytes)
        bytesCopied += bytes
        bytes = read(buffer)
    }
    return bytesCopied
}

The actual reading happens with the read function. If you read the documentation for that, it will return the amount of bytes read (including 0) and -1 when the end of the stream has been read.

This works fine for files, but not for network sockets. The way a network socket works is that the situation where nothing is read is common (it means the other side didn’t send any data). And in general, you want to support processing the requests without closing the connection. In other words, readBytes() is a nice shortcut, but not valid for network streams. Handle the reading of your data yourself, because at that point you can use the data stream to parse it to know whether your request is complete or you need to wait again (for more data from the network).

1 Like

inputstream.copyTo

is also hanging up and in am not able to get method to read the data i passed in output stream ( i also tried to manually copy bytes in a while loop which again hanged up ), while i need just the first line where request URI is present but i don’t want to rely on unreliable hacks

private fun server(switchStatus:AtomicBoolean){
        Log.e("dbg","inside sever function and proceeding to bind")
        val server = ServerSocket(4000,1000, Inet4Address.getByName("0.0.0.0"))
        println("listening to socket")

        runOnUiThread{binding.tvmain.text = "listening to socket"}
        while(true){
            Log.e("dbg","waiting to accept connection")

            if (switchStatus.equals(false)) {break}
            val socket = server.accept()
            val inputStream = socket.getInputStream()

            Log.e("reading","Getting the reader")
            //val reader = inputStream.reader()

            Log.e("reading","reading all data as text")
            // code stuck here

            val data :OutputStream = ByteArrayOutputStream()

            inputStream.copyTo(data, DEFAULT_BUFFER_SIZE)


            Log.e("e"," ")


           // Log.e("output",data.toArray().toString())
            val outputStream = socket.getOutputStream()

            Log.e("writing","writing the output")
            outputStream.write(response.toByteArray())

            Log.e("closing","closing output stream")
            outputStream.flush()
            outputStream.close()


            Log.e("closing","closing socket")
            socket.close()

        }
    }

What you need to do is read blocks independently, not in their entirety. That wouldn’t be a hack. The problem is that you are trying to use shortcut methods that read the entire stream (possibly only stopping when the destination buffer runs out of space). These methods are not valid for network streams in the way you are trying to do.

A network socket consists of two streams, A→B and B→A, but you can only close the socket, not half.

i will look more into java sockets library
i guess i am mixing up my previous experience of Go / C into this

Thanks for your help

The problem you are having is not really a kotlin/java problem, but one with the general way in which network sockets work. The only way to avoid this and have the elegant (read everything) api would be to use threads or coroutines. Basically, read everything will read everything, even if knowing what is everything will only be known once the stream has been closed. What you want is “read everything that is currently available”. Currently doesn’t work as time is continuous. The way it works in reality is that you use a protocol that allows you to identify when you have read a full message. (Either using message lengths or some sort of delimiter). If you look at how HTTP works, you will notice this: “use content-length” or empty line after all request headers for http 1 and packets + sizes for http 2