B4J Question How to trap java.net.SocketException: Connection reset [solved]

Didier9

Well-Known Member
Licensed User
Longtime User
Here is how I am opening a TCP socket:
B4X:
    tcpSocket.Connect( IPAddress, EthernetPort, 5000 )
    Wait For tcpSocket_Connected( Connected As Boolean )
    If tcpSocket.Connected = True Then
        Astream.Initialize( tcpSocket.InputStream, tcpSocket.OutputStream, "AStream" )
        Log( "TCP socket is open" )
    Else
        Log( "TCP socket failed to open" )
    End If

That works fine, unless the socket is already open by another client. In that case, the server does open the socket but closes it immediately after the SYN-ACK/ACK ("Connection is forcefully rejected"). I do get this in the log:
B4X:
TCP socket is open
java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:210)
    at java.net.SocketInputStream.read(SocketInputStream.java:141)
    at java.net.SocketInputStream.read(SocketInputStream.java:127)
    at anywheresoftware.b4a.randomaccessfile.AsyncStreams$AIN.run(AsyncStreams.java:216)
    at java.lang.Thread.run(Thread.java:748)
java.net.SocketException: Connection reset by peer: socket write error
    at java.net.SocketOutputStream.socketWrite0(Native Method)
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
    at java.net.SocketOutputStream.write(SocketOutputStream.java:143)
    at anywheresoftware.b4a.randomaccessfile.AsyncStreams$AOUT.run(AsyncStreams.java:355)
    at java.lang.Thread.run(Thread.java:748)
Error: (SocketException) java.net.SocketException: Connection reset by peer: socket write error
Error: (SocketException) java.net.SocketException: Connection reset by peer: socket write error
TimeOut: 0
I tried to separately declare a Sub tcpSocket( Connected as Boolean ) event to catch the socket being closed right after it is opened but
the event does not fire and my application is left to believe the socket is open.
How can I trap the SocketException event?

Here is a simple example that shows the problem (there will be no point running it if you do not have the proper target running the proper code to talk to it).
 

Attachments

  • dev 202110161758.zip
    6.9 KB · Views: 257
Last edited:

EnriqueGonzalez

Well-Known Member
Licensed User
Longtime User
Sub tcpSocket( Connected as Boolean )
is this your whole sub? it should be the same as with wait for:
sub tcpSocket_Connected( Connected As Boolean )

if you add a wait for it will take precedense over the normal sub but just once, the next time it will trigger the normal sub correctly
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
is this your whole sub? it should be the same as with wait for:
sub tcpSocket_Connected( Connected As Boolean )

if you add a wait for it will take precedense over the normal sub but just once, the next time it will trigger the normal sub correctly
This is the tcpSocket_Connected() event:
B4X:
Sub tcpSocket_Connected( Connected As Boolean )
    Log( "tcpSocket.Connected = " & Connected )
End Sub ' tcpSocket_Connected()
and I do not get anything in the log. Apparently SocketException does not fire the Connected() event.
The socket is seemingly open but nothing comes out (I have WireShark connected and it does not show anything)
 
Last edited:
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
to answer your question, you trap exceptions with try/catch.
as to exactly where you add such a block is unclear at this
point. (we can't see what comes after your test for
connectivity.)

if you didn't initialize your asynch stream, and if you did
absolutely nothing after connecting, what happens?
if nothing happens, then the exception is occurring when
you start to do something. that's where your try/catch would
wrap your attempt to do something. eg, i would suggest
initializing the async stream in the try. if that doesn't trigger
the catch, then go a little further. what would come next?

(and, certainly, if the connect failed in the first place, you should
return from the sub immediately. as it is, you just indicate it failed
and, apparently, simply continue as if it hadn't failed.)
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
to answer your question, you trap exceptions with try/catch.
as to exactly where you add such a block is unclear at this
point. (we can't see what comes after your test for
connectivity.)

if you didn't initialize your asynch stream, and if you did
absolutely nothing after connecting, what happens?
if nothing happens, then the exception is occurring when
you start to do something. that's where your try/catch would
wrap your attempt to do something. eg, i would suggest
initializing the async stream in the try. if that doesn't trigger
the catch, then go a little further. what would come next?

(and, certainly, if the connect failed in the first place, you should
return from the sub immediately. as it is, you just indicate it failed
and, apparently, simply continue as if it hadn't failed.)
The target is a microcontroller with lwip stack and DHCP, which works fine but only supports one client at a time and has only one port open, so if a second client tries to open the same socket, the target sends a reset (FIN-ACK-RST) and closes the port.

If I run a single copy of my app, all works well as expected. The port is opened and packets go back and forth until the port is closed. My app uses AStream to send/receive data and that works fine. There is a small issue which is that the target closes the port after 1 minute of inactivity and apparently the B4J app does not get notified that the port is closed (tcpSocket_Connected( False) does not fire), so it seemingly keeps the port open and of course if I try to send data, I get no response. This is a problem I would like to fix too but not the biggest problem at the moment.

The bigger problem at the moment is that if I run a second copy of the app and try to connect to the same socket, the connection seems to succeed (the tcpSocket_Connected( True ) event is fired,) but when I try to write to the socket through AStream_Write(), I get the java exception but no event in B4J, so B4J thinks the socket is open.
I then have to manually close the socket on both apps and I can then reconnect one app.
I tried to enclose the AStream_Write() statement in Try/Catch but it does not catch anything, it seems the problem occurs after that, probably due to java rearranging things to its liking...

This is a fairly large app so it's impractical to post the entire project (and my employer may object...). I will try to simplify it to the minimum necessary but that may take a little while.

I do have an older version of a very similar app written in VB 6.0 and the OS (or the VB runtime) correctly reports the "Port forcefully closed" message when trying to open the port on the second copy of the app.
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User

drgottjr

re-reading your response, I will try to enclose all the network related bits in Try/Catch. I think most of them already are but not all so I will try that.
I am using Wait For in a number of places and I have observed that it made debugging (including single stepping) quite a bit more difficult, so Try/Catch may help.
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
I have confirmed that the java SocketException occurs AFTER sending data, not when initializing AStream. Maybe I should try without using AStream? It seems like it is adding a layer of processing between java and the app and it may not be propagating the java error messages correctly?
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
i don't think asynch has anything to do with what you're experiencing. you're basically dealing with a dedicated server that only has 1 port open and only connects with 1 client. unless you're main application is gui-bound, i don't see the advantage of asynch in his case? this is an android
fascination with not blocking the main thread.

i took a quick look at the java code for the network and randomaccessfile libraries. many of the methods throw exceptions, which means they are candidates for try/catch (otherwise, you crash if an exception is thrown and you weren't ready for it since you were warned).

there appears to be no b4x event raised by an unexpected disconnect. so you need a way of determining whether or not you're connected. i'm saying the easiest way to determine this is to write to your stream from within try/catch. the java.net.Socket class does afford 2 methods which may or may not indicated whether a socket has been disconnected and/or closed. but you have to run those methods (which might work with a javaobject). since neither of those methods raises an event, it's up to you to keep asking if you're still connected. not ideal, but not unheard of.

you can use the 1 port/1 client situation in your favor. your app connects and in try/catch tries to write. if catch is triggered, you know the server is talking to somebody else. if you survice the catch, you know you're in the clear.

as far as timing out due to inactivity, you have to keep the connection alive ("stay with me! stay with me!"). if your socket is a global object, you can have it write something periodically while your application is otherwise idling. writing within try/catch, of course. a timer could be an option, but since you already know the server will cut the connection without any activity, it is up to you to keep the connection alive.
 
Last edited:
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
Are you handling AStream Terminated and Error events?
I have the Error event, but not Terminated. Off work until Monday, I will try then.
Thanks, that may be it.

Edit: I have added it, it makes no difference, the event it not triggered.
 
Last edited:
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
having an event tells you no more than try/catch. the lost connection occurs for 1 of 2 reasons; my suggestions tell you which has occurred. this allows you to act accordingly. it would be silly to try to reconnect if another client were active, and it's easy to avoid disconnect due to inactivity. just having an event - and assuming it's raised - doesn't tell you why the connection was lost. for the event to be effective, you would need flags to let you know which was set when the event occurred. my guess is both an error event and a terminated event will simply tell you io exception. you would have to figure out why.
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
there appears to be no b4x event raised by an unexpected disconnect. so you need a way of determining whether or not you're connected. i'm saying the easiest way to determine this is to write to your stream from within try/catch. the java.net.Socket class does afford 2 methods which may or may not indicated whether a socket has been disconnected and/or closed. but you have to run those methods (which might work with a javaobject). since neither of those methods raises an event, it's up to you to keep asking if you're still connected. not ideal, but not unheard of.
Something that needs help :)
The issue at the moment is that the crash occurs "outside the code" (I don't know how else to put it), I have a try/catch around the astream_write() and it does not catch it.

you can use the 1 port/1 client situation in your favor. your app connects and in try/catch tries to write. if catch is triggered, you know the server is talking to somebody else. if you survive the catch, you know you're in the clear.
I am fine with that if I can make it work.

as far as timing out due to inactivity, you have to keep the connection alive ("stay with me! stay with me!"). if your socket is a global object, you can have it write something periodically while your application is otherwise idling. writing within try/catch, of course. a timer could be an option, but since you already know the server will cut the connection without any activity, it is up to you to keep the connection alive.
Yes, the short inactivity timer is intentional. There are two types of operation if you will, "interactive" where data flows constantly both ways and "command line" where it does not. We want the target to disconnect if left in command mode for too long with no traffic (partly to make sure we can reconnect quickly if something goes wrong since we accept only one client at a time, partly for security reasons).
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
having an event tells you no more than try/catch. the lost connection occurs for 1 of 2 reasons; my suggestions tell you which has occurred. this allows you to act accordingly. it would be silly to try to reconnect if another client were active, and it's easy to avoid disconnect due to inactivity. just having an event - and assuming it's raised - doesn't tell you why the connection was lost. for the event to be effective, you would need flags to let you know which was set when the event occurred. my guess is both an error event and a terminated event will simply tell you io exception. you would have to figure out why.
I am fine with that, I just want to catch it and not crash. problem is try/catch does not seem to work.
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
i have my understanding of what i think occurs. i apologize for insisting on the
same points.

if there is another client online already, can you tell me exactly what happens
when you log in with another client and do nothing for 1 minute? does the
same thing happen (if anything) if you repeat the operation a number of times?

if there is another client online already, can you tell me exactly what happens
when you log in with another client and start to write on the socket with no
try/catch? does the same thing happen (if anything) if you repeat the operation
a number of times?

if there is another client online already, can you tell me exactly what happens
when you log in with another client and start to write on the socket within a
try/catch block? does the same thing happen (if anything) if you repeat the
operation a number of times?

in other words, can you cause the disconnect to occur when another client is
on the line? when it occurs, can you catch it? i would like to get the 2 client
problem out of the way. letting a crash occur when it may be trappable is just
bad programming. you seem to be saying that it's not trappable. i just want to
make sure which disconnect we're talking about. let's start with multiple clients.

also, you've introduced a new wrinkle with "command line" and "interactive mode".
i would think you could end a command line script due to inactivity (my isp logs
me out all the time when i forget i've ssh'd in for more than 5 minutes).
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
i have my understanding of what i think occurs. i apologize for insisting on the
same points.

if there is another client online already, can you tell me exactly what happens
when you log in with another client and do nothing for 1 minute? does the
same thing happen (if anything) if you repeat the operation a number of times?

if there is another client online already, can you tell me exactly what happens
when you log in with another client and start to write on the socket with no
try/catch? does the same thing happen (if anything) if you repeat the operation
a number of times?

if there is another client online already, can you tell me exactly what happens
when you log in with another client and start to write on the socket within a
try/catch block? does the same thing happen (if anything) if you repeat the
operation a number of times?

in other words, can you cause the disconnect to occur when another client is
on the line? when it occurs, can you catch it? i would like to get the 2 client
problem out of the way. letting a crash occur when it may be trappable is just
bad programming. you seem to be saying that it's not trappable. i just want to
make sure which disconnect we're talking about. let's start with multiple clients.

also, you've introduced a new wrinkle with "command line" and "interactive mode".
i would think you could end a command line script due to inactivity (my isp logs
me out all the time when i forget i've ssh'd in for more than 5 minutes).
All good questions, I will have wireshark running while I try those, but that will be Monday as I need to be on the corporate network because I can't get to the target through the VPN.
In the meantime, I have found a stripped down app that I used to develop the network code. I will clean it up and make sure it does the same thing, and that one I can post the source code for it, even though without my target, it may not help a lot.
Thanks for the help, apparently there are not too many people able to dig into the intricacies of TCP/IP.
 
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
OK, I have my simplified app doing apparently the same thing with a small Ethernet/RS485 adapter driving a microcontroller that should be pretty close to what my target at work looks like.
The Ethernet/RS-485 adapter is configured to accept one client with no timeout (for now).

Here is my test environment:
Laptop runs 2 copies of the app, one under debug, the other runs the exe.
I also have wireshark running, looking for ip traffic to and from the Ethernet adapter.
The Ethernet/RS-485 adapter is connected to the uC board via RS-485. The serial protocol is a simple command/response protocol originally knows as the SABus protocol (framing bytes, parity bits and checksum).

I first connect the exe to my target (the first 3 lines on the Wireshark screen shot below, above the first red line) and send a command/get a response (the next 4 lines, between the two red lines). The default command "0" (ID query) is sent when you click the Send button.

Then the second copy of the app (the debug one) tries to connect to the same socket (SYN, SYN-ACK, ACK). My app says it is connecting (Connect button turns green) but the server is clearly closing the connection (FIN-ACK-FIN-ACK, the lines below the second red line) and neither AStream_Error or AStream_Terminated fire and there is no data going out when I click the Send button.

1634390605063.png


After I did this, I added the Log( xxxx ) statements in the Terminated and Error events and tried again and this time the debug app crashed with this error message:
B4X:
    Call B4XPages.GetManager.LogEvents = True to enable logging B4XPages events.
Trying to connect to: 192.168.1.10
b4xmainpage._astream_terminated (java line: 199)
java.lang.RuntimeException: Object should first be initialized (Exception).
	at anywheresoftware.b4a.AbsObjectWrapper.getObject(AbsObjectWrapper.java:49)
	at anywheresoftware.b4a.objects.B4AException.getMessage(B4AException.java:38)
	at b4j.example.b4xmainpage._astream_terminated(b4xmainpage.java:199)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at anywheresoftware.b4a.BA.raiseEvent2(BA.java:108)
	at anywheresoftware.b4a.BA$3.run(BA.java:264)
	at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
	at java.security.AccessController.doPrivileged(Native Method)
	at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(PlatformImpl.java:294)
	at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
	at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
	at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
	at java.lang.Thread.run(Thread.java:748)

I am puzzled by the "java.lang.RuntimeException: Object should first be initialized (Exception)" message since I have the AStream_Terminated event declared, even though it does not seem to have been firing since there is no message in the log.

The exe app is still running and connected and messages still go back and forth.

I have attached the project to the first post in this thread.
If you want to play with it, I can worm the target through the firewall and give you a domain name/port via private message so you can try.
 
Last edited:
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
This is the Wireshark screenshot when trying to connect the debug app. Same as the first time but it crashes reliably now, even though the socket is cleanly closed by the server and the PC acknowledges it (FIN-ACK-FIN-ACK).

1634392761640.png


B4X:
Call B4XPages.GetManager.LogEvents = True to enable logging B4XPages events.
Trying to connect to: 192.168.1.10
b4xmainpage._astream_terminated (java line: 199)
java.lang.RuntimeException: Object should first be initialized (Exception).
	at anywheresoftware.b4a.AbsObjectWrapper.getObject(AbsObjectWrapper.java:49)
	at anywheresoftware.b4a.objects.B4AException.getMessage(B4AException.java:38)
	at b4j.example.b4xmainpage._astream_terminated(b4xmainpage.java:199)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at anywheresoftware.b4a.BA.raiseEvent2(BA.java:108)
	at anywheresoftware.b4a.BA$3.run(BA.java:264)
	at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
	at java.security.AccessController.doPrivileged(Native Method)
	at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(PlatformImpl.java:294)
	at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
	at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
	at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
	at java.lang.Thread.run(Thread.java:748)
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
ok, this is a lot, but i am interested. by the way, i just came across this post from 2014:)
 

Attachments

  • asynch.PNG
    asynch.PNG
    25.6 KB · Views: 227
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
I have an old VB 6.0 client app that still runs and with it, the Socket object reports the "peer closing" status as it happens, through the Error handler.
The Wireshark traffic looks exactly the same.
 
Last edited:
Upvote 0

Didier9

Well-Known Member
Licensed User
Longtime User
ok, this is a lot, but i am interested. by the way, i just came across this post from 2014:)
Yes, I saw that, that's why I thought about going around AStream.
But in my opinion, this is an issue that should be fixed, so if I can help make it better, I am willing to try :)
 
Upvote 0
Top