TCP Client-Side Not Recieveing Data Properly VB.NET - vb.net

I'm trying to make a simple client-side application to recieve small text data, compare it and then does something on client machine depending on what server sent.
Server Logic: The server side is made in java, so can't change anything there. Server sends string "abc001" on connecting to client.
Client Logic: Client recieves the string "abc001" from server & checks if it's recieved string is the same as "abc001", then does something accordingly.
Problem: When the client recieves data, I display it in msgbox. But instead of just "abc001", there pops up an extra blank msgbox(image included).
Client Code - On Start:
Try
' declare vals
Dim ip As String = "127.0.0.1"
Dim port As Integer = 5000
' set client
_client = New TcpClient(ip, port)
' disable cross thread calls checking
CheckForIllegalCrossThreadCalls = False
' recieve msg
Threading.ThreadPool.QueueUserWorkItem(AddressOf RecieveMessages)
Catch ex As Exception
MsgBox(ex.ToString)
End Try
Client Code - Recieve Data
Private Sub RecieveMessages(state As Object)
Try
While True
Dim ns As NetworkStream = _client.GetStream()
Dim toRecieve(_client.ReceiveBufferSize) As Byte
ns.Read(toRecieve, 0, CInt(_client.ReceiveBufferSize))
Dim txt As String = Encoding.ASCII.GetString(toRecieve)
MsgBox(txt)
End While
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub
MsgBox 1
MsgBox 2
How to not get the blank msgbox. Even when compared, the data recived does not match parameters. Tried to use delay, tried fixing the buffer size to 6 bytes but no use.. Any help is appreciated. Thanks.
EDIT 1: Tried my best to figure it out but can't.. Tried cleaning the returned string data and even tried storing each return data in array. Saw the stack and it says the msgbox has "nothing" in it. It's null.. I don't even know what to do.. Here's the code for strings clean:
Private Sub RecieveMessages(state As Object)
Dim message(0) As String
Dim command_raw, command_clean, command As String
Dim counter As Integer = 0
Try
While True
Dim ns As NetworkStream = _client.GetStream()
Dim toRecieve(_client.ReceiveBufferSize) As Byte
ns.Read(toRecieve, 0, CInt(_client.ReceiveBufferSize))
Dim txt As String = Encoding.ASCII.GetString(toRecieve)
message(0) = txt
command_raw = message(0)
command_clean = command_raw.Replace(vbCrLf, Nothing)
command = command_clean.Substring(0, 6)
MsgBox(command)
End While
Catch ex As Exception
MsgBox(ex.ToString)
End Try
End Sub

Related

vb.net async stream write/read problems

I’m after some help with a problem i have been working on for the past few days but i can't seem to get it to work correctly.
I have multiple clients connecting to a server, the server needs to keep a list of connected clients and remove them from the list if the client disconnects, I have this bit working correctly.
Once a client is connected the server may call upon the client for some information about its state by sending a few bytes of data to which the client responds with 2 bytes of data. Based on this response the server will complete any one of number of different tasks.
I have had this working synchronously, though now I am trying to make the function asynchronous and I’m running in to an issue. The best I can tell my function that request the information from the client is completing before the client responds and is returning incorrect data, if I print the data received from the client I can see it is the correct information.
This is my 1st time working with asynchronous functions and connections so it’s highly likely I’ve got it completely wrong, I have looked at lots of example code but I can seem to find any that sheads any light on my issue.
This is what I have at the moment:
'create the collection instance to store connected clients
Private clients As New List(Of TcpClient)
'declare a variable to hold the listener instance
Private listener As TcpListener
'declare a variable to hold the cancellation token source instance
Private tokenSource As CancellationTokenSource
Private recvTsk As Task
Private Rreply As New List(Of Byte)
Private Async Sub startTCPListenerServer()
'get port from ini file
Dim netPort = SettingsIniFile.GetString("Setup", "NetworkPort", "")
While True
'create a new cancellation token source instance
tokenSource = New CancellationTokenSource
'create a new listener instance bound to the desired address and port
listener = New TcpListener(IPAddress.Any, netPort)
'start the listener
listener.Start()
While True
Try
Dim client As TcpClient = Await listener.AcceptTcpClientAsync
clients.Add(client)
Dim clientIP As String = client.Client.RemoteEndPoint.ToString
ListBox1.Items.Add(clientIP)
Try
'begin reading from the client's data stream
Using stream As NetworkStream = client.GetStream
Dim buffer(client.ReceiveBufferSize - 1) As Byte
Dim read As Integer = 1
'if read is 0 client has disconnected
While read > 0
recvTsk = New Task(Sub()
For i = 0 To read - 1
'data recived at this point is correct
Rreply.Add(buffer(i))
Next
End Sub, tokenSource.Token)
read = Await stream.ReadAsync(buffer, 0, buffer.Length, tokenSource.Token)
recvTsk.Start()
End While
'client gracefully closed the connection on the remote end
End Using
Catch ocex As OperationCanceledException
'the expected exception if this routines's async method calls honor signaling of the cancelation token
'*NOTE: NetworkStream.ReadAsync() will not honor the cancelation signal
Catch odex As ObjectDisposedException
'server disconnected client while reading
Catch ioex As IOException
'client terminated (remote application terminated without socket close) while reading
Finally
'ensure the client is closed - this is typically a redundant call, but in the
'case of an unhandled exception it may be necessary
'remove the client from the list of connected clients
clients.Remove(client)
client.Close()
ListBox1.Items.Remove(clientIP)
'remove the client's task from the list of running tasks
'clientTasks.Remove(client.Task)
End Try
Catch odex As ObjectDisposedException
'listener stopped, so server is shutting down
Exit While
End Try
End While
For i As Integer = clients.Count - 1 To 0 Step -1
clients(i).Close()
Next
tokenSource.Dispose()
End While
'signal any processing of current clients to cancel (if listening)
tokenSource.Cancel()
'abort the current listening operation/prevent any new connections
listener.Stop()
'End If
End Sub
Async Function sendToPod(message() As Byte, podNum As Integer) As Task(Of Byte)
If clients.Count = 0 Then
Else
Dim podIP As String
'get ip address as string from ini file
podIP = SettingsIniFile.GetString("NetworkSettings", "Pod" & podNum & "IP", "")
Dim currentClient As TcpClient = Nothing
For Each client As TcpClient In clients
Dim clientIP As String = (CType(client.Client.RemoteEndPoint, IPEndPoint).Address.ToString())
If clientIP = podIP Then
currentClient = client
End If
Next
If currentClient IsNot Nothing Then
'get the current client, stream, and data to write
Dim stream As NetworkStream = currentClient.GetStream
Dim buffer() As Byte = message
'wait for the data to be sent to the remote
Await stream.WriteAsync(buffer, 0, buffer.Length)
recvTsk.Wait()
Return Rreply(1)
End If
End If
End Function
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Try
Me.TextBox1.Text = Await sendToPod({"&HAB", "&HAD", "&HFF", "&HFF"}, 1)
Catch
End Try
End Sub
End Class

How do I upload data to a server with valid SSL certificate using a client vb.net program?

I am working on a program and uploads a shipping manifest to a the shippers website. When I try to upload, I get a nondescript error back from their server, and when checking with the shipper, they tell me that "there is an issue with the SSL" I am using.
I've spent quite a bit of time piecing together code that, from what I seem to understand, is supposed to work, but I'm not making any progress. As far as I know everything else is fine with the upload, but there is a problem with my SSL certificate
If I understand what this code is supposed to do correctly, I should get a certificate from the shippers website, which allows certification to my program for a space of time during which I can upload the data. I'm really not sure that this is what my code is doing at all, but the only code examples I have seen show it something like this.
Here's my code with the URLs changed:
'This references a custom class that compiles the manifest I'm going to upload
Dim StringToUpload As String = Compile_Manifest(MyDate, UseTestDB)
Dim webClient As New System.Net.WebClient
webClient.Credentials = System.Net.CredentialCache.DefaultCredentials
'From what I understand,
'this is supposed to set up properties used in next section of code
System.Net.ServicePointManager.SecurityProtocol = Net.SecurityProtocolType.Ssl3
System.Net.ServicePointManager.ServerCertificateValidationCallback = _
AddressOf AcceptAllCertifications
'I can see that this reaches the server,
'but I don't know how it relates to the next section of code
'that actually uploads the manifest
Dim ServerRequest As System.Net.WebRequest = _
System.Net.WebRequest.Create("https://www.certify.some-shippper.com:443/somefolder")
Dim ServerResponse As System.Net.WebResponse
ServerResponse = ServerRequest.GetResponse()
ServerResponse.Close()
'This code works for the upload of the manifest,
'and it seems the above code is unrelated and does not use a SSL certificate.
'When this code runs I get the same error back from the shippers server,
'indicating an issue with my SSL, with or without the two sections of code above.
Dim StrResult As String = ""
Dim WrappedString As String = TransmitPLD.WrapPldFile(StringToUpload)
'This references a custom class that wraps the data to upload
'in information from the shipper.
Dim ByesToUpload As Byte() = _
System.Web.HttpUtility.UrlEncodeToBytes(WrappedString, _
System.Text.ASCIIEncoding.ASCII)
Dim Result As Byte() = _
webClient.UploadData("https://www.certify.some-shippper.com:443/somefolder", _
ByesToUpload)
StrResult = System.Web.HttpUtility.UrlDecode(Result, _
System.Text.ASCIIEncoding.ASCII)
MessageBox.Show(StrResult)
So it turns out I went about it the wrong way. I needed to upload my data through System.Net.WebRequest and it takes care of the certificates for me. Not implementing all the parts of the code I needed, it didn't handle the retrieval of the shipper's certificate.
In case anyone else gets confused about the matter like I did, here's my working code for anyone to see, adapt and use. My resource for fixing the code (and by that I mean starting from scratch) was the MSDN page for the WebRequest class, and it has code examples much the same as what I have below in C++, C#, and VB.NET and here is the link.
First there are some global variables that need to be set and class that needs to be created for to store the upload response:
' This is set in the function that Upload function
' and uploads the data in the ReadCallback sub
Private Shared WrappedString As String
' This is used to wait for the callback in the Upload function
Private Shared allDone As New Threading.ManualResetEvent(False)
Friend Class RequestState
' This class stores the request state of the request.
Public request As Net.WebRequest
Public Sub New()
request = Nothing
End Sub ' New
End Class ' RequestState
Then there is a sub needed for the upload part web request which will be called further below in the upload function:
Private Shared Sub ReadCallback(asynchronousResult As IAsyncResult)
Try
Dim myRequestState As RequestState = CType(asynchronousResult.AsyncState, RequestState)
Dim myWebRequest As Net.WebRequest = myRequestState.request
' End the request.
Dim streamResponse As IO.Stream = myWebRequest.EndGetRequestStream(asynchronousResult)
' Convert the string into a byte array.
Dim byteArray As Byte() = System.Text.Encoding.ASCII.GetBytes(WrappedString)
' Write the data to the stream.
streamResponse.Write(byteArray, 0, byteArray.Length)
streamResponse.Close()
' Allow the main thread to resume.
allDone.Set()
Catch ex As Exception
Throw New Exception("Error in " & Reflection.MethodBase.GetCurrentMethod.Name.ToString & " **" & ex.Message, ex)
End Try
End Sub ' ReadCallback
Finally, this is the function that should be called to upload the data, which uses all the code above:
Public Shared Function Upload(ByVal MyDate As Date) As String
Dim StrResult As String = ""
UploadSucess = False
Try
' This is my code that builds the manifest that I want to upload
Dim StringToUpload As String = Compile_PLD200(MyDate)
WrappedString = TransmitPLD.WrapPldFile(StringToUpload)
Dim myWebRequest As Net.WebRequest
myWebRequest = Net.WebRequest.Create("https://www.some.website.com:443/someplace")
' Create an instance of the RequestState and assign
' myWebRequest to it's request field.
Dim myRequestState As New RequestState()
myRequestState.request = myWebRequest
myWebRequest.ContentType = "multipart/mixed; boundary=BOUNDARY"
myRequestState.request.Method = "POST"
' Start the asynchronous 'BeginGetRequestStream' method call.
Dim r As IAsyncResult = CType(myWebRequest.BeginGetRequestStream(AddressOf ReadCallback, myRequestState), IAsyncResult)
' Pause the current thread until the async operation completes.
allDone.WaitOne()
' Send the Post and get the response.
Dim myWebResponse As Net.WebResponse = myWebRequest.GetResponse()
Dim streamResponse As IO.Stream = myWebResponse.GetResponseStream()
Dim streamRead As New IO.StreamReader(streamResponse)
Dim readBuff(256) As [Char]
Dim count As Integer = streamRead.Read(readBuff, 0, 256)
While count > 0
Dim outputData As New [String](readBuff, 0, count)
Console.WriteLine(outputData)
count = streamRead.Read(readBuff, 0, 256)
StrResult += outputData
End While
' Close the Stream Object.
streamResponse.Close()
streamRead.Close()
' Release the HttpWebResponse Resource.
myWebResponse.Close()
Catch ex As Exception
Throw New Exception("Error in " & Reflection.MethodBase.GetCurrentMethod.Name.ToString & " **" & ex.Message, ex)
End Try
Return StrResult
End Function ' Upload
Again here is the MSDN page for the WebRequest class which has a code example too.
Hope this helps anyone who was stuck like I was. And any criticisms as to the implementation of the code are welcome. This just happen to do what I want, I can't say it is the most efficient implementation.

VB.Net Sockets Invoke

I am using vb.net 2010 and I have created a program that uses sockets to transfer data between our windows server and a unix server. The code was originally from a Microsoft sample project hence my little understanding of it.
Everything was fine until I had the idea of changing the program into a service. The Invoke command is not accessable from a service. I think I understand why but more importantly how do I get around it or fix it?
' need to call Invoke before can update UI elements
Dim args As Object() = {command, data}
Invoke(_processInStream, args)
Someone please help I am desperate to finish this program so I can move on :)
Below is the rest of the class, there is a server socket class too but I didnt want to complicate things?
Public Class srvMain
' start the InStream code to receive data control.Invoke callback, used to process the socket notification event on the GUI's thread
Delegate Sub ProcessSocketCommandHandler(ByVal command As NotifyCommandIn, ByVal data As Object)
Dim _processInStream As ProcessSocketCommandHandler
' network communication
Dim WithEvents _serverPRC As New ServerSocket
Dim _encryptDataIn() As Byte
Dim myConn As SqlConnection
Dim _strsql As String = String.Empty
Protected Overrides Sub OnStart(ByVal args() As String)
' watch for filesystem changes in 'FTP Files' folder
Watch()
' hookup Invoke callback
_processInStream = New ProcessSocketCommandHandler(AddressOf ProcessSocketCommandIn)
' listen for Ultimate sending signatures
_serverPRC.Start(My.Settings.listen_port_prc)
myConn = New SqlConnection(My.Settings.Mill_SQL_Connect)
End Sub
Protected Overrides Sub OnStop()
' Add code here to perform any tear-down necessary to stop your service.
End Sub
' this is where we will break the data down into arrays
Private Sub processDataIn(ByVal data As Object)
Try
If data Is Nothing Then
Throw New Exception("Stream empty!")
End If
Dim encdata As String
' decode to string and perform split(multi chars not supported)
encdata = Encoding.Default.GetString(data)
_strsql = encdata
myConn.Open()
Dim commPrice As New SqlCommand(_strsql, myConn)
Dim resPrice As SqlDataReader = commPrice.ExecuteReader
'********************************THIS MUST BE DYNAMIC FOR MORE THAN ONE NATIONAL
If resPrice.Read = True And resPrice("ats" & "_price") IsNot DBNull.Value Then
'If resPrice("ats" & "_price") Is DBNull.Value Then
' cannot find price so error
'natPrice = ""
'natAllow = 2
'End If
natPrice = resPrice("ats" & "_price")
natAllow = resPrice("ats" & "_allow")
Else
' cannot find price so error
natPrice = ""
natAllow = 2
End If
myConn.Close()
' substring not found therefore must be a pricing query
'MsgBox("string: " & encdata.ToString)
'natPrice = "9.99"
Catch ex As Exception
ErrHandle("4", "Process Error: " + ex.Message + ex.Data.ToString)
Finally
myConn.Close() ' dont forget to close!
End Try
End Sub
'========================
'= ServerSocket methods =
'========================
' received a socket notification for receiving from Ultimate
Private Sub ProcessSocketCommandIn(ByVal command As NotifyCommandIn, ByVal data As Object)
' holds the status message for the command
Dim status As String = ""
Select Case command
Case NotifyCommandIn.Listen
'status = String.Format("Listening for server on {0} ...", CStr(data))
status = "Waiting..."
Case NotifyCommandIn.Connected
'status = "Connected to Ultimate" ' + CStr(data)
status = "Receiving..."
Case NotifyCommandIn.Disconnected
status = "Waiting..." ' disconnected from Ultimate now ready...
Case NotifyCommandIn.ReceivedData
' store the encrypted data then process
processDataIn(data)
End Select
End Sub
' called from socket object when a network event occurs.
Private Sub NotifyCallbackIn(ByVal command As NotifyCommandIn, ByVal data As Object) Handles _serverPRC.Notify
' need to call Invoke before can update UI elements
Dim args As Object() = {command, data}
Invoke(_processInStream, args)
End Sub
End Class
Any help is appreciated
Many thanks
Invoke is a member of System.Windows.Forms.Form, and it is used to make sure that a certain method is invoked on the UI thread. This is a necessity in case the method in question touches UI controls.
In this case it looks like you simply can call the method directly, i.e.
instead of
Dim args As Object() = {command, data}
Invoke(_processInStream, args)
you can simply write
ProcessSocketCommandIn(command, data)
Also, in this case you can get rid of the _processInStream delegate instance.

Creating instances of forms inside a thread

i am trying to create a new instance of a form if its not allready been created the only problem is is that the instance creation is inside a thread.
Private Sub doRead(ByVal ar As System.IAsyncResult)
Dim totalRead As Integer
Try
totalRead = client.GetStream.EndRead(ar) 'Ends the reading and returns the number of bytes read.
Catch ex As Exception
'The underlying socket have probably been closed OR an error has occured whilst trying to access it, either way, this is where you should remove close all eventuall connections
'to this client and remove it from the list of connected clients.
End Try
If totalRead > 0 Then
'the readBuffer array will contain everything read from the client.
Dim receivedString As String = System.Text.Encoding.UTF8.GetString(readBuffer, 0, totalRead)
messageReceived(receivedString)
End If
Try
client.GetStream.BeginRead(readBuffer, 0, BYTES_TO_READ, AddressOf doRead, Nothing) 'Begin the reading again.
Catch ex As Exception
'The underlying socket have probably been closed OR an error has occured whilst trying to access it, either way, this is where you should remove close all eventuall connections
'to this client and remove it from the list of connected clients.
MessageBox.Show(ex.ToString)
End Try
End Sub
The problem lies when the form is created on the line .showDialog() it stops here untill the application is closed. ive tryed using .show() but then the new "Convo window just hangs"
Private Sub messageReceived(ByVal message As String)
Dim data() As String = message.Split("|"c)
Select Case data(0)
Case "MESSAGE"
Dim chatDialog As New RichTextBox
Try
If conversations.ContainsKey(data(1)) Then
Dim convoWindow As ChatWindow
convoWindow = New ChatWindow
convoWindow = conversations.Item(data(1))
chatDialog = convoWindow.RichTextBox1
Else
Try
Dim convoWindow As New ChatWindow()
conversations.Add(data(1), convoWindow)
convoWindow = conversations.Item(data(1))
convoWindow.ShowDialog()
chatDialog = convoWindow.RichTextBox1
AppendTextChatWindows(data(2), chatDialog)
Thanks
Houlahan

Don't get any data from socket when data should be there, and no exceptions raised, connection is open. Using DataAvailable to wait for data

I have a problem reading data from an RFID-reader. I connect to the reader by tcp and wait for DataAvailable to be true, then reading the data until I got a end of data character. Then I just go back and waiting for a new DataAvailable. This is done in a own thread for the function.
There seems to be some kind of timeout, If I don't got any data in a couple of minutes, then it just sits there in the do/loop waiting for DataAvailable. I hold the card to the RFID reader, it beeps, but there is no data available. I don't get any exceptions, and the information says that the clientsocket is still connected. Are there anything more I can check?
If I put the card to the reader in a minute-interval it seems as this will never occur. So 2-3 minutes idle:ing seems to do this.
Here are my code to read data from the socket, I have taken away some irrelevant code:
Sub test(ByVal ip As String, ByVal port As Integer)
' this sub is meant to run forever
Try
Dim clientSocket As New System.Net.Sockets.TcpClient()
clientSocket.Connect(ip, port)
Using serverStream As NetworkStream = clientSocket.GetStream()
Do 'loop forever or until error occur
'Every new dataentry starts here
Dim inStream(0) As Byte
Dim returndata As String = ""
Do 'loop forever
Do Until serverStream.DataAvailable 'loop until data exists to read
If clientSocket.Connected = False Then
'this will never happen.
'but if there are more than 5 minutes between data then
'it never got data again as if no data was sent.
Exit Sub
End If
Application.DoEvents()
Loop
'there is data to read, read first byte and
serverStream.Read(inStream, 0, 1)
If inStream(0) = 13 Then
'got end of data
'exit loop if reading chr 13.
returndata &= System.Text.Encoding.ASCII.GetString(inStream)
Exit Do
End If
Loop
GotData(returndata)
Loop
End Using
Catch ex As Exception
' handle error
Finally
'close connection if open
End Try
End Sub
I found out that socket.Connected only reports the status for when the last command was runned on the connection.
So in the Do Until serverStream.DataAvailable loop I used this trick to check if the connection was closed instead:
Dim test As Boolean = clientSocket.Client.Poll(10, System.Net.Sockets.SelectMode.SelectRead)
If test = True And serverStream.DataAvailable = False Then
'restart connection
End If
So now finally got control over what is happening and know that its because of the client connection is closed that I dont got any data.
So, then I figured, now that I know that the connection is closed, how do I prevent it? That was easier, just send data to the tcpip-server every 10 second and it will hold it open.
The result that works for me (this is not the production code, just an example of the solution):
Dim s As Date = Now
Do Until serverStream.DataAvailable
Dim r As Boolean = clientSocket.Client.Poll(10, System.Net.Sockets.SelectMode.SelectRead)
If DateDiff(DateInterval.Second, s, Now) > 10 Then
Dim dta(0) As Byte
dta(0) = 0
clientSocket.Client.Send(dta)
s = Now
End If
If r = True And serverStream.DataAvailable = False Then
'restart sub
Exit Sub
End If
loop
So now it doesnt even close and need to restart every x minutes.
My problems are solved and Im a happy coder. ;)