Var loopx As Boolean = True
While loopx = True
Print(Me.ReadAll(Encodings.UTF8).ToText)
Print("")
Var payload As String = Input
If payload = "killme" Then
loopx = False
Exit
End If
Me.Write(payload + chr(0) + EndOfLine)
Me.Flush
Wend
Quit
Client DataAvailable event:
Var sh As Shell = New Shell
sh.ExecuteMode = shell.ExecuteModes.Synchronous
Var received As String = Me.ReadAll.ToText
sh.Execute(received.ToText + EndOfLine)
Var result As String = sh.ReadAll.ToText
Me.Write(result + chr(0) + EndOfLine)
Me.Flush
The server app is running on my MacBook and client app is running on my Raspberry Pi in my office (behind NAT/Firewall). Everything is running fine so far, I can update my Raspberry or reboot it. Thatâs exactly what I was looking for and I did it on my own without having to pay for it, without compromising my security in my office by opening or forwarding ports or exposing my Raspberry Pi to the internet.
But there is a problem. When I enter for example âls -laâ to display all files and folders in the current directory, I have to press [Enter] twice in order to see the results of âls -laâ. What I can say so far, is that the result is immediately sent to the server after pressing the [Enter] key once, which means that there is something wrong with my server code (because it will only display the results after pressing the [Enter] key once more).
Wild guesses okay? Iâm thinking that the (buffer?) doesnât have the response (yet) prior to your .ReadAll, and then you issue a 2nd request and the prior requests results are there in the buffer. If you move the variable âresultâ outside of this block where it can persist longer, then maybe that could help?
This may be way off base - itâs late, but I hope itâs some help.
Itâs somewhat odd to have a null byte in the middle of a string. Perhaps itâs supposed to come after the end-of-line?
If the server is expecting a null-terminated string then it would stop reading after the first null byte. The first EOL would therefore appear at the beginning of the second message rather than the end of the first. Hence, youâd need to send a second message to make the first get noticed.
Var loopx As Boolean = True
Print(Me.ReadAll(Encodings.UTF8).ToText)
Print("")
While loopx = True
Var payload As String = Input
If payload = "killme" Then
loopx = False
Exit
End If
Me.Write(payload)
Me.Flush
Print(Me.ReadAll(Encodings.UTF8).ToText)
Print("")
Wend
Quit
Client:
Var sh As Shell = New Shell
sh.ExecuteMode = shell.ExecuteModes.Synchronous
Var received As String = Me.ReadAll.ToText
sh.Execute(received.ToText)
sh.Poll
Var result As String = sh.ReadAll.ToText
Me.Write(result)
Me.Flush
Do me a favor and get rid of the two calls to ToText in the client. The data comes in as a string and you are needlessly converting to the Text type and back to String twice.
In terms of why it takes two commands to get a result, the Input method blocks the main thread. That means that after a command is sent and it starts waiting for the next command, no data can come in from the socket either.
So when you call me.Flush followed by Me.Readall on the server, those happen immediately probably while the socket is still sending. Then you immediately start waiting for more input and the app effectively hangs.
You might want to make it so the app doesnât call Input until after youâve received a response or a sufficient timeout has occurred.
Var loopx As Boolean = True
Print(Me.ReadAll(Encodings.UTF8).ToText)
Print("")
While loopx = True
Var payload As String = Input
If payload = "killme" Then
loopx = False
Exit
End If
Me.Write(payload)
Me.Flush
Var waitUntil As Integer = System.Ticks + 30
While System.Ticks < waitUntil
Wend
Print(Me.ReadAll(Encodings.UTF8).ToText)
waitUntil = System.Ticks + 30
While System.Ticks < waitUntil
Wend
Wend
Quit
// Sender (socket):
Var myCommand As String = "ls -la" + EndOfLine.Unix // Use unix to always use a known type
Socket.Write(myCommand)
// Reader (socket), DataAvailable event:
// You need a buffer as String property on the class
Var isDataAvailable As Boolean = (me.lookAhead(Encodings.UTF8) <> "")
If isDataAvailable Then
buffer = buffer + me.ReadAll(Encodings.UTF8)
Var lines(-1) As String = buffer.Split(EndOfLine.Unix)
If lines.count > 0 Then
Var lastIndex As Integer = lines.lastIndex
For i As integer = 0 To lastIndex
If i = lastIndex Then
// The last line did not had an ending EndOfLine, this is our new buffer
buffer = lines(i)
Exit For i
else
// This is a Line handle it, call a method or raise a custom event..
If line(i) = "ls -la" Then
// Your ls -la command handle here
End If
end If
Next i
End If
Var sh As Shell = New Shell
sh.ExecuteMode = shell.ExecuteModes.Synchronous
Var isDataAvailable As Boolean = (Me.Lookahead <> "")
If isDataAvailable Then
buffer = buffer + Me.ReadAll(Encodings.UTF8)
Var lines(-1) As String = buffer.Split(EndOfLine.UNIX)
If lines.Count > 0 Then
Var lastIndex As Integer = lines.LastIndex
For i As Integer = 0 To lastIndex
If i = lastIndex Then
buffer = lines(i)
Exit For i
Else
sh.Execute(lines(i))
sh.Poll
Var result As String = sh.ReadAll
Me.Write(result)
Me.Flush
End If
Next
End If
End If
Still not working. Exactly the same result as before.
I changed it to Me.Write(result + EndOfLine.UNIX), no difference at all.
Client:
Var loopx As Boolean = True
Print(Me.ReadAll(Encodings.UTF8))
Print("")
While loopx = True
Var payload As String = Input
If payload = "killme" Then
loopx = False
Exit
End If
Me.Write(payload + EndOfLine.UNIX)
Me.Flush
'Var waitUntil As Integer = System.Ticks + 30
'While System.Ticks < waitUntil
'Wend
Print(Me.ReadAll(Encodings.UTF8))
Wend
Quit
Well if you just keep looping nothing is gonna happen. is this a console application or desktop ?
Your loop is not ever calling anything to request the data from the system.
ISTM that this whole approach is wrong. If you try to do all this work inside the dataAvailable event handler, you have to send data, WAIT until itâs sent, WAIT until thereâs data available, then read it (or reverse the sequence for the other end).
Inside an event handler, you have NO means of doing a WAIT. Your data available handler should do no more than resuming a thread where you do the real work. That thread will have started the I/O, then paused itself. It will then stay paused until an event handler resumes it. That could also be done by a timerâs event handler if you want to incorporate timeouts in the business, which in the real world you will want to.