javaandroidhttpkotlinhttpurlconnection

Reading and Writing from Server in loop in the same time on Android


I need to create a connection to the server and read messages from the server for some time. At the same time, I need to send a string to the server every X seconds to update the data. I am using HttpUrlConnection and the following code:

NTRIPClient.kt

class NTRIPClient {

private val bufferSize = ByteArray(64)
private val crlf = "\r\n"

private var inputStream: BufferedInputStream? = null

fun startConnection(gga: String, usbService: UsbService) {
    con = url.openConnection() as HttpURLConnection?
    con?.doOutput = true
    con?.setChunkedStreamingMode(0)
    con?.setRequestProperty("Ntrip-GGA", gga)
    con?.setRequestProperty("Connection", "Keep-Alive")
    con?.setRequestProperty("Accept-Encoding", "identity")

    try {
        inputStream = BufferedInputStream(con!!.inputStream)
        var readBuffer = inputStream!!.read(bufferSize)
        while (readBuffer > 0) {
            usbService.write(bufferSize)
            readBuffer = inputStream!!.read(bufferSize)
        }
    } catch (e: IOException) {
        e.printStackTrace()
    } finally {
        con?.disconnect()
    }
}

fun updateGGA(gga: String) {
    try {
        val outputStream = OutputStreamWriter(con!!.outputStream)  //this line create error
        outputStream.write(gga + crlf)
        outputStream.close()
    } catch (e: IOException) {
        e.printStackTrace()
    }
}

Call NTRIPClient in ViewModel.kt

fun createNtripConnection(usbService: UsbService){
        ntripScope.launch {
            awaitAll(
                async {
                    Log.d(TAG, "createNtripConnection: START")
                    ntripClient.startConnection(currentGGA, usbService)
                },
                async {
                    delay(5000)
                    ntripClient.updateGGA(currentGGA)
                }
            )
        }
    }

When I run the method createNtripConnection everything works fine, but when it comes time to execute the method updateGGA I get the following error:

W/System.err: java.io.IOException: unexpected end of stream on com.android.okhttp.Address@5170b14c
        at com.android.okhttp.internal.http.Http1xStream.readResponse(Http1xStream.java:203)
        at com.android.okhttp.internal.http.Http1xStream.readResponseHeaders(Http1xStream.java:129)
        at com.android.okhttp.internal.http.HttpEngine.readNetworkResponse(HttpEngine.java:750)
        at com.android.okhttp.internal.http.HttpEngine.readResponse(HttpEngine.java:622)
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:475)
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:411)
        at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:248)
        at com.hq.advian.newtwork.NTRIPClient.startConnection(NTRIPClient.kt:43)
        at com.hq.advian.viewmodel.ArViewModel$createNtripConnection$1$1.invokeSuspend(ArViewModel.kt:207)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
W/System.err:     at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
    Caused by: java.io.EOFException: \n not found: size=0 content=...
        at com.android.okhttp.okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:202)
        at com.android.okhttp.internal.http.Http1xStream.readResponse(Http1xStream.java:188)
        ... 14 more

If in the updateGGA at the very beginning I try to close the inputStream, on this line I get java.lang.NullPointerException. Can you help with this? Or there are other tools to solve this problem?


Solution

  • So i found the solution. HttpUrlConnection can't read and write data in the same time. To do this, you need to use a Socket. First you need to create a Socket and connect to the host:

    InetAddress address = InetAddress.getByName(new URL("{your_url/your_mount_point}").getHost());
    Socket socket = new Socket(address, PORT_NUMBER);
    System.out.println(socket.isConnected());
    

    If you connected successfully, then in the console you will see true.

    Now you have to open two streams to communicate with the server: InputStream and OutputStream:

    PrintWriter output = new PrintWriter(socket.getOutputStream(), true);
    BufferedInputStream input = new BufferedInputStream(socket.getInputStream());
    

    Now you can send GET, POST and others requests. To do this, we will use a PrintWriter:

    String requestMessage = "GET /{your_mount_point} HTTP/1.1\r\n";
    output.println(requestMessage);
    

    We use message GET /{path} {protocol (HTTP/1.1 for example)}. At the end of each line you must use CRLF \r\n. Then you can add the necessary headers according to the scheme:

    output.println("{header name}: {header value}\r\n");
    
    output.println("Connection: Keep-Alive");
    output.println("Accept-Encoding: identity");
    

    After that, you can read data from the server. In my case, this is an endless stream of messages, so I will use the following option:

    byte[] buffer = new byte[128];
    int readBuffer = input.read(buffer);
    while (readBuffer > 0) {
       System.out.println(Arrays.toString(buffer));
       readBuffer = input.read(buffer);
    }
    

    If during data reading you need to change the header, you can send the string to the server again:

    output.println("Connection: close");
    

    Full method looks like this:

    void createSocket() {
            try {
                InetAddress address = InetAddress.getByName(new URL("your_url/your_mount_point").getHost());
                Socket socket = new Socket(address, PORT_NUMBER);
                System.out.println(socket.isConnected());
    
                PrintWriter output = new PrintWriter(socket.getOutputStream(), true);
    
                BufferedInputStream input = new BufferedInputStream(socket.getInputStream());
    
                String requestMessage = "GET /{your_mount_point} HTTP/1.1\r\n";
                output.println(requestMessage);
                output.println("Ntrip-Version: Ntrip/2.0\r\n");
                output.println("Connection: Keep-Alive");
                output.println("Accept-Encoding: identity");
                output.println("\r\n");
    
                byte[] buffer = new byte[128];
    
                int readBuffer = input.read(buffer);
                while (readBuffer > 0) {
                    System.out.println(Arrays.toString(buffer));
                    readBuffer = input.read(buffer);
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }