Android Question Can a socket be connected and closed at the same time?

Sandman

Expert
Licensed User
Longtime User
I whipped up some code to help out with a little logging, but surprisingly often it crashes with java.io.IOException: Socket Closed in the line commented with CRASH HERE. I've wrapped everything carefully to make sure the socket should be in good shape, but even though it apparently is connected, it's considered closed in the line after. How is this even possible? Am I missing something obvious?

logThis_Error and logThis_Terminated are never called.

And on the receiving end is just a dead simple receiver that dumps out whatever is sent to it, so I'm very sure that side isn't part of the problem. (It's just the command ncat -k -l 5010 running on a Linux machine.)

B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    ' For logging purposes only
    Private socket As Socket   
End Sub


Public Sub logThis (text As String)
   
    Dim astream As AsyncStreams
    Dim data() As Byte
    Dim Successful As Boolean = False

    If Not(socket.IsInitialized) Then
        socket.Initialize("socket")
    End If

    If Not(socket.Connected) Then
        socket.Connect("192.168.1.14", 5010, 30000)
        Wait For socket_Connected (Successful As Boolean)
    End If
   
    ' Exit early if it wasn't successful
    If Not(Successful) Then
        Log("logThis: Not successful")
        Return
    End If

    If socket.Connected Then
        astream.Initialize(Null, socket.OutputStream, "logThis") ' <-- CRASH HERE
        data = (text & CRLF).GetBytes("UTF8")
        astream.Write(data)
    Else
        Log("logThis: COULD NOT CONNECT")
    End If
   
End Sub


Public Sub logThis_Error
    Log("logThis: ERROR")
    If LastException.IsInitialized Then
        Log(LastException.Message)
    Else
        Log("LogThis: No exception message available")
    End If
End Sub


Public Sub logThis_Terminated
    Log("logThis: TERMINATED")
    If LastException.IsInitialized Then
        Log(LastException.Message)
    Else
        Log("LogThis: No exception message available")
    End If
End Sub
 

Diceman

Active Member
Licensed User
I whipped up some code to help out with a little logging, but surprisingly often it crashes with java.io.IOException: Socket Closed in the line commented with CRASH HERE. I've wrapped everything carefully to make sure the socket should be in good shape, but even though it apparently is connected, it's considered closed in the line after. How is this even possible? Am I missing something obvious?

B4X:
  ...
    If socket.Connected Then
        astream.Initialize(Null, socket.OutputStream, "logThis") ' <-- CRASH HERE
        data = (text & CRLF).GetBytes("UTF8")
        astream.Write(data)
    Else
        Log("logThis: COULD NOT CONNECT")
    End If

I'm no expert, but shouldn't you be executing aStream.InitializePrefix instead of aStream.Initialize?
See https://www.b4x.com/android/forum/threads/b4x-asyncstreams-tutorial.7669/#content

Or you could follow Didier9's suggestion and see if the malfunctioning socket killed Schrödinger's cat.
 
Upvote 0

Sandman

Expert
Licensed User
Longtime User
Initialize AsyncStreams once after the socket is connected

Ok, I'll try that, thanks.


Your code will create a new AsyncStreams every call. This is a mistake.

But how can this be a mistake? Is the AsynchStreams more tightly coupled to the socket than what can be expected from my code? As the AsynchStream is defined in the sub, I thought it would cease to exist once the sub ends, causing the socket to also lose its reference to it. Now I'm starting tu suspect that the socket doesn't release the reference, which means my code just keeps adding more and more AsynchStreams to the socket, causing problems.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
thought it would cease to exist once the sub ends,
That's a mistake. Objects are "killed" when there are no more live references to them. In this case AsyncStreams will never be killed as it creates two threads that work with the socket and hold reference to the AsyncStreams object.
 
Upvote 0

Sandman

Expert
Licensed User
Longtime User
Objects are "killed" when there are no more live references to them.

That makes perfect sense. I have no idea why I thought the sub had more power than the reference, thanks for explaining.

Sidenote... I wonder how many hard-to-find bugs happen because one does what I did: Define one variable as a process global, and then another in a sub, and using the sub one in the process one. (I wonder if this is something the linter could catch in a reasonably simple way.)
 
Upvote 0

Diceman

Active Member
Licensed User
That makes perfect sense. I have no idea why I thought the sub had more power than the reference, thanks for explaining.

Sidenote... I wonder how many hard-to-find bugs happen because one does what I did: Define one variable as a process global, and then another in a sub, and using the sub one in the process one. (I wonder if this is something the linter could catch in a reasonably simple way.)

I don't know if this can help you or not.
I always define my local variables with a prefix like "loc" for "locStream" (or perhaps "lstream") and parameters passed to a sub start with "a" as in "aStream". I don't normally use a prefix on global variables, or you could use "gblStream" or "gStream" etc. Just by looking at the variable you know where it is defined. It makes debugging much much easier and I'm not tearing my hair out wondering what the scope of the variable is. I could never go back to programming without using variable prefixes.

I used to use "_" as the prefix for local variables in a different language so local variables are like "_Stream" and is very readable, but the "_" disables obfuscation in some B4x subs. :(
 
Upvote 0
Top