Text communication between applications with TCP Sockets in VB.Net - vb.net

I've got a problem to make two applications to send text-data between themselves.
The message is transmitted without any problems, the answer is received too. But, there is a lot of a "New line" char in the end of the string send/received on each side.
I guess it's because of I'm reading the full buffer; I've tried to remove all Chr(10) and Chr(13); I also tried to trim the string, but it didn't worked.
Here the code I use :
Client Side :
Dim cl As New TcpClient
cl.Connect("127.0.0.1", 2000)
Dim str As NetworkStream = cl.GetStream
Dim HelloInBytes As Byte() = Encoding.UTF8.GetBytes("Hello")
str.Write(HelloInBytes, 0, HelloInBytes.Length)
Dim Buffer(cl.ReceiveBufferSize) As Byte
str.Read(Buffer, 0, cl.ReceiveBufferSize)
Console.WriteLine(Encoding.UTF8.GetChars(Buffer))
Server Side :
Dim srv As New TcpListener(IPAddress.Any, 2000)
srv.Start()
Dim cl As TcpClient = srv.AcceptTcpClient
Dim str As NetworkStream = cl.GetStream
Dim buf(cl.ReceiveBufferSize) As Byte
str.Read(buf, 0, cl.ReceiveBufferSize)
Dim res As Byte() = Encoding.UTF8.GetBytes("World")
str.Write(res, 0, res.Length)
Is there a way to "clean" the received string ?
Thanks for help.
EDIT : Solution :
It Works with Harzcle solution.
I found another solution which is to use this function on the received string :
Public Function CleanString(ByRef Str As String)
Return Str.Replace(Encoding.UTF8.GetChars({0, 0, 0, 0}), Nothing)
End Function
UTF8 works on 4 bytes, and when I read the stream and I put it into a buffer, if there is no char, the 4 bytes stay on a 0 value.

Use Flush() after you write into the buffer
str.Write(HelloInBytes, 0, HelloInBytes.Length)
str.Flush()
And
str.Write(res, 0, res.Length)
str.Flush()
Edit:
You can use a delimiter or something like that.
Client side:
Dim delimiterChar as Char = "|"
Dim out As Byte() = System.Text.Encoding.UTF8.GetBytes(txtOut.Text + delimiterChar)
server.Write(outStream, 0, outStream.Length)
server.Flush()
And Server side:
Dim delimiterChar as Char = "|"
Dim Stream As NetworkStream = clientSocket.GetStream()
Stream.Read(bytesFrom, 0, CInt(client.ReceiveBufferSize))
Dim data As String = System.Text.Encoding.UTF8.GetString(bytesFrom)
data = data.Substring(0, data.IndexOf(delimiterChar)) 'From 0 to delimiter

This will remove all null characters at the end of the received string
client_content = client_content.Replace(Chr(0), Nothing)
To remove new lines:
client_content = client_content.Replace(vbLf, Nothing)

Related

Simple TCP Client Program for Send Hex Bytes using VB.Net 2015

I tried to send Hex bytes through the TCP using VB.net. And receive the response of data.
Following code I used,
Dim tcpClient As New System.Net.Sockets.TcpClient()
tcpClient.Connect("192.168.1.10", 502)
Dim networkStream As NetworkStream = tcpClient.GetStream()
If networkStream.CanWrite And networkStream.CanRead Then
' Do a simple write.
Dim sendBytes As [Byte]() = {&H0, &H4, &H0, &H0, &H0, &H6, &H5, &H3, &HB, &HD3, &H0, &H1}
networkStream.Write(sendBytes, 0, sendBytes.Length)
' Read the NetworkStream into a byte buffer.
Dim bytes(tcpClient.ReceiveBufferSize) As Byte
networkStream.Read(bytes, 0, CInt(tcpClient.ReceiveBufferSize))
' Output the data received from the host to the console.
Dim returndata As String = Encoding.ASCII.GetString(bytes)
TextBox1.Text = ("Host returned: " + returndata)
Else
If Not networkStream.CanRead Then
TextBox1.Text = "cannot not write data to this stream"
tcpClient.Close()
Else
If Not networkStream.CanWrite Then
TextBox1.Text = "cannot read data from this stream"
tcpClient.Close()
End If
End If
End If
When I send sendbytes data, I did not get any data. When I send data, master automatically sends me data but I did not get any data. This is Modbus communication.
I can only see Host returned:
The data is there, but you cannot see it because it starts with a null byte (&H0 or just 0). Most text controls that encounter a null byte interprets that as the end of the string and thus doesn't render the rest of the text.
GetString() merely takes the bytes as is and converts them into the respective chars with the same values. It is up to you to turn the result into a readable format.
The solution is to skip GetString() and instead iterate the array, converting every byte into a hex or number string.
Also, two very important things:
You shouldn't use TcpClient.ReceiveBufferSize in your code as it is used for the internal buffer. You should always decide the buffer size on your own.
Since TCP is a stream-based protocol the application layer has no notion of packets. One 'send' from the server usually does not equal one 'receive'. You might receive more or less data than what the first packet actually is. Use the return value from NetworkStream.Read() to determine how much has been read.
You then need to read up on the Modbus documentation and see if its data contains something that indicates the end or the length of a packet.
'Custom buffer: 8 KB.
Dim bytes(8192 - 1) As Byte
Dim bytesRead As Integer = networkStream.Read(bytes, 0, bytes.Length)
Dim returndata As String = "{"
'Convert each byte into a hex string, separated by commas.
For x = 0 To bytesRead - 1
returnData &= "0x" & bytes(x).ToString("X2") & If(x < bytesRead - 1, ", ", "}")
Next
TextBox1.Text = "Host returned: " & returnData

Issue sending big string over TCP

I have the following function to send and receive data it works OK for short strings like 150 bytes, but with a string of 2500 bytes it get stuck.
I tried to send some data with HTWin and nothing get the other end of the net.
So receiver on the other end never get even a character.
I tried also with the old Hyperterminal with same result.
Private Function SendReport(ByVal Msg As String, ByVal Host As String, ByVal Port As String) As String
Try
Dim Tx As New TcpClient()
Dim stream As NetworkStream = Nothing
Dim CloseStream As Boolean = False
Dim LingerMode As New LingerOption(True, 5)
' String to store the response ASCII representation.
Dim responseData As [String] = [String].Empty
Tx.NoDelay = True
Tx.LingerState = LingerMode
Tx.SendTimeout = 10000
Tx.ReceiveTimeout = 10000
Tx.Connect(Host, Port)
' Translate the passed message into ASCII and store it as a Byte array.
Dim data As [Byte]() = System.Text.Encoding.ASCII.GetBytes(Msg)
' Get a client stream for reading and writing.
' Stream stream = client.GetStream();
stream = Tx.GetStream()
CloseStream = True
'stream.WriteTimeout = 100
' Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length)
'Tx.Connected
' Receive the TcpServer.response.
' Buffer to store the response bytes.
data = New [Byte](256) {}
' Read the first batch of the TcpServer response bytes.
Dim bytes As Int32 = stream.Read(data, 0, data.Length)
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes)
If CloseStream = True Then
stream.Close()
End If
Tx.Close()
Return responseData
Catch ex As Exception
WriteRTBLog(ex.Message, Color.Red)
WriteRTBLog(ex.StackTrace, Color.DarkRed)
Return "Error"
End Try
End Function
If I split the big string into smaller one and call this function over and over all the data reach the other end.
Also, I need to get an ACK packet that is big too and the code must wait for and special character that indicates the end.
I was thinking in to create a Thread with a TcpListener but, Is possible to have a TcpListener in the same port of a TcpClient?
The whole idea is to send a big string that is separated by an special character and finished with another special character.
The other end receive the data, split the string using the first special character and send one ACK by every item in the split function.
And in the last ACK send the second special character to indicate the end of the communication, so my application can process the received data properly.
I think I'm drowning in a glass of water.

Convert this line of code from VB.NET to C#?

How do I convert the following line of code from VB.NET to C#.
Dim bytes(tcpClient.ReceiveBufferSize) As Byte
I got the following line from the developerfusion web site, but it's giving me wrong results in my program.
byte[] bytes = new byte[tcpClient.ReceiveBufferSize + 1];
Here is an example of my entire code in Visual Basic.
Dim tcpClient As New System.Net.Sockets.TcpClient()
TcpClient.Connect(txtIP.Text, txtPort.Text)
Dim networkStream As NetworkStream = TcpClient.GetStream()
If networkStream.CanWrite And networkStream.CanRead Then
Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytes(txtSend.Text.Trim())
networkStream.Write(sendBytes, 0, sendBytes.Length)
' Read the NetworkStream into a byte buffer.
TcpClient.ReceiveBufferSize = 52428800 '50 MB
'Do I need to clean the buffer?
'Get the string back (response)
Dim bytes(tcpClient.ReceiveBufferSize) As Byte
networkStream.Read(bytes, 0, CInt(TcpClient.ReceiveBufferSize))
' Output the data received from the host to the console.
Dim returndata As String = Encoding.ASCII.GetString(bytes)
Visual Basic specifies the maximum bound of the array instead of the length of the array (arrays start at index 0), so your conversion added an extra byte. In your code however the correct way would be:
byte[] bytes = new byte[tcpClient.ReceiveBufferSize];
If you get wrong results, tell us what exactly is wrong. Maybe it's another part of the code.
Edit: Remove the \0 like this:
byte[] bytes = new byte[tcpClient.ReceiveBufferSize];
int bytesRead = networkStream.Read(bytes, 0, tcpClient.ReceiveBufferSize);
// Output the data received from the host to the console.
string returndata = Encoding.ASCII.GetString(bytes,0,bytesRead);
Edit: Even better to read the data in packets, so you don't need to reserve a large buffer upfront:
byte[] bytes = new byte[4096]; //buffer
int bytesRead = networkStream.Read(bytes, 0, bytes.Length);
while(bytesRead>0)
{
// Output the data received from the host to the console.
string returndata = Encoding.ASCII.GetString(bytes,0,bytesRead);
Console.Write(returndata);
bytesRead = networkStream.Read(bytes, 0, bytes.Length);
}

Invalid character in a Base-64 string when attempting decryption

I have a encryption/decryption method that works just fine with one exception. When I attempt to read in encrypted text from a text file and then decrypt it I get the following error.
Invalid character in a Base-64 string
The strange thing is if I just read the encrypted text into a textbox and then copy and pate it into another text box that decrypts used the same decryption method it works just fine. No errors and the decryption proceeds. I am listing the decryption method and method used to read in the text file below.
Decryption Method
Public Shared Function DecryptUserString(ByRef cipheredText As String, ByRef password As String) As String
Dim RijndaelManagedObj As New RijndaelManaged
Dim RijndaelEncObj As ICryptoTransform, MD5Obj As New MD5CryptoServiceProvider
Dim DecryptedBytes As Byte(), EncryptedData As Byte()
Dim PasswordBytes As Byte() = New ASCIIEncoding().GetBytes(password)
Dim UTF8Encoding As System.Text.Encoding = System.Text.Encoding.UTF8
'A modified Base64 is sent with ~ and - so it can be sent as a form post
EncryptedData = Convert.FromBase64String(Replace(Replace(cipheredText, "~", "+"), "-", "="))
RijndaelManagedObj.BlockSize = 128
RijndaelManagedObj.KeySize = 128
RijndaelManagedObj.Mode = CipherMode.ECB
RijndaelManagedObj.Padding = PaddingMode.None
RijndaelManagedObj.Key = MD5Obj.ComputeHash(PasswordBytes)
RijndaelEncObj = RijndaelManagedObj.CreateDecryptor()
DecryptedBytes = RijndaelEncObj.TransformFinalBlock(EncryptedData, 0, EncryptedData.Length)
If DecryptedBytes.Length > 0 Then
DecryptUserString = UTF8Encoding.GetString(DecryptedBytes, 0, DecryptedBytes.Length)
If DecryptedBytes.Length = 0 Then DecryptUserString = New ASCIIEncoding().GetString(DecryptedBytes)
Else
DecryptUserString = ""
End If
End Function
Method to read text from file
Private Function ReadText(ByVal TextFilePath As String) As String
Using ReadStream As FileStream = File.OpenRead(TextFilePath)
Dim FileTextBuilder As New StringBuilder()
Dim DataTransit As Byte() = New Byte(ReadStream.Length) {}
Dim DataEncoding As New UTF8Encoding(True)
While ReadStream.Read(DataTransit, 0, DataTransit.Length) > 0
FileTextBuilder.Append(DataEncoding.GetString(DataTransit))
End While
Return FileTextBuilder.ToString()
End Using
End Function
Can't you use File.ReadAllText() method to read the whole file and then decrypt the same way you do with textboxes?
I know, if file is huge that's not a good idea, but you can give it a try to see if file is well saved or if you're reading it bad.

storing first byte as string from network stream

I need to store the first byte of data read from the network stream as a string, so I can call it back later.
prinf(" While 1
Dim tcpListener As New TcpListener(IPAddress.Any, 80) ' Listen to port given
Console.WriteLine("Waiting for connection...")
tcpListener.Start()
'Accept the pending client connection and return 'a TcpClient initialized for communication.
Dim tcpClient As TcpClient = tcpListener.AcceptTcpClient()
Console.WriteLine("Connection accepted.")
' Get the stream
Dim networkStream As NetworkStream = tcpClient.GetStream()
' Read the stream into a byte array
Dim bytes(tcpClient.ReceiveBufferSize) As Byte
networkStream.Read(bytes, 0, CInt(tcpClient.ReceiveBufferSize))
' Return the data received from the client to the console.
Dim clientdata As String = Encoding.ASCII.GetString(bytes)
Console.WriteLine(("Client Sent: " + clientdata))
' Return the data received from the client to the console.
Dim responseString As String = "Hello"
'Dim chat_name As String = "Name"
Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytes(responseString)
networkStream.Write(sendBytes, 0, sendBytes.Length)
Console.WriteLine(("Response: " + responseString))
tcpClient.Close() 'Close TcpListener and TcpClient
tcpListener.Stop()
End While");
Thats my server ^ everything works fine, but I need the 1st piece of data read to be stored, such as if I get "Name" it should be stored in an array
Thanks
You'll need to define exactly what you mean by "1st piece of data" - is this data delimited in some form (like HTTP headers - key/value pairs are delimited by carriage-return line-feed)? Length-prefixed (like HTTP bodies when the Content-Length header is specified)? You almost certainly don't just want the first byte.
If you were hoping to just send the name and then send something else, without any indication of the fact that they're different bits of data, you're going to be disappointed. Streams are just sequences of bytes - there's nothing (built-in) to say "read what the client sent in their first API call".
This should work:
Dim strFirstByte as string = vbNullString
While 1
' ... Your code ...
Dim bytes(tcpClient.ReceiveBufferSize) As Byte
networkStream.Read(bytes, 0, CInt(tcpClient.ReceiveBufferSize))
If strFirstByte = vbNullString Then strFirstByte = bytes(0).ToString("X2")
' ... The rest of your code ...
End While