I have problem about socket to send multiple hex in one send to socket
Here the detail :
Private Sub sendACK()
Dim msgACK As String
Dim sendBytes As Byte()
tmpStr = ""
list.Clear()
msgACK = "33CC"
For j = 1 To Len(msgACK)
list.Add(Mid(msgACK, j, 2))
j += 1
Next
For Each tmpStr In list
sendBytes = HexToBytes(tmpStr)
clientSocket.BeginSend(sendBytes, 0, sendBytes.Length, SocketFlags.None, New System.AsyncCallback(AddressOf OnSend), clientSocket)
Next
End Sub
Public Function HexToBytes(ByVal s As String) As Byte()
Dim bytes As String() = s.Split(" "c)
Dim retval(bytes.Length - 1) As Byte
For ix As Integer = 0 To bytes.Length - 1
retval(ix) = Byte.Parse(bytes(ix), System.Globalization.NumberStyles.HexNumber)
Next
Return retval
End Function
Private Sub OnSend(ByVal ar As IAsyncResult)
clientSocket = ar.AsyncState
clientSocket.EndSend(ar)
Thread.Sleep(100)
End Sub
==> List as arraylist
That code will be result :
Socket send 33
end send
Socket send CC
end send
============================
The program should be sending in one time like this :
Socket send 33 CC
end send
============================
is there any idea about convert string "33CC" into byte and then that program just sending 1 time in outter "for each" ?
thanks for reading and answering....
GBU
Your assumption is incorrect. It does indeed send both bytes at once. You are only calling BeginSend once and you are giving it both bytes, so if it is receiving them at all on the other end, then it is indeed sending them. In fact, there is no difference at all between sending them individually or sending them together. Since the socket works as a stream, the length of time between each byte being sent is largely irrelevant. There will be no way on the receiving end to know whether the two bytes were sent together or separately. All the receiving end will know is that the two bytes were sent in that order. If you think they are being sent as two separate "sends" on the receiving end, it sounds like you are making some invalid assumptions about how to read the data from the socket.
However, I should mention that the way you are sending the bytes, by first creating a hex string and then parsing it, is a bit silly. If you need to parse it as a string, because you are reading the hex values from a text file, or something, that's fine, but otherwise, you should just use hex byte literals in your code rather than strings, for instance:
Dim sendBytes As Byte() = {&H33, &HCC}
Related
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
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.
I'm making a VB.NET application that requires a very fast sending/receiving of strings ("commands") but have this little problem: when I send 2 or more consecutive string very quickly with the client, the server receives only a single string containing all the previous strings.
This is my sending Sub (Client):
Public Sub send(ByVal s As String)
Dim temp() As Byte = UTF8.GetBytes(s)
Try
stream.Write(temp, 0, temp.Length)
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
This is my receiving Sub (Server, using a thread):
Public Sub listen()
Do
If client.Available > 0
Dim temp(client.Available - 1) As Byte
stream.Read(temp, 0, temp.Length)
Dim text As String = UTF8.GetString(temp)
'some checks on the string (example = if text.StartWith("something") then...)
End If
Loop
End Sub
Here's an example of what happens:
Client:
send("1"),
send("2"),
send("hello"),
send("18").
String received by Server: "12hello18".
How can I solve this?
Thanks.
You are assuming that Read reads a "message" at a time. TCP is not message-based. It offers you a boundaryless stream of bytes. Look into message framing. Often, this problem is solved by prepending the length of each message as an int before sending the message itself.
I'm coding an ascynchronous socket client for transferring files (following this Microsoft article) and notice that using BeginReceive corrupts the transfer because it adds a single Null character/chr(0) at the end of each packet. What could be causing this issue? I thought it might be the sending side, but I tested it with SendFile and had the same result.
In the Microsoft article it converts the bytes to an ASCII string and appends it to a StringBuilder. I want to save the bytes on-the-fly, so I barely modified the ReceiveCallback like so:
Private Shared Sub ReceiveCallback(ByVal ar As IAsyncResult)
Dim state As StateObject = CType(ar.AsyncState, StateObject)
Dim client As Socket = state.workSocket
Dim bytesRead As Integer = client.EndReceive(ar)
If bytesRead > 0 Then
FileIO.FileSystem.WriteAllBytes(Application.StartupPath & "\test.exe", state.buffer, True)
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, New AsyncCallback(AddressOf ReceiveCallback), state)
Else
receiveDone.Set()
End If
End Sub
The problem is a misconception on how Receive, or BeginReceive & EndReceive work.
When you call Receive and give it a buffer and a size, you are specifying the maximum amount of data to receive. It is the bytesRead that tells you how much you actually received. You need to only write that number of bytes to your output file, as only that portion of your buffer was populated with data.
See here for more details:
http://msdn.microsoft.com/en-us/library/w3xtz6a5
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