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