It's posible to define the UDP sourceport? - vb.net

I have a WinForm application made it in VB.NET and I need to answer in the same port that I receive the UDP message but with the code that I have running the application source port is being chosen by the O.S., or it seems that.
Private Sub UdpSend(ByVal txtMessage As String)
Dim pRet As Integer
GLOIP = IPAddress.Parse(IpRemotaLbl.Text)
GLOINTPORT = RemotePortLbl.Text
MyUdpClient.Connect(GLOIP, GLOINTPORT)
bytCommand = Encoding.ASCII.GetBytes(txtMessage)
pRet = MyUdpClient.Send(bytCommand, bytCommand.Length)
'Console.WriteLine("No of bytes send " & pRet)
PrintLog("No of bytes send " & pRet)
End Sub
In example, if I receive the UDP message on port 8082 the answer, currently, is being sent from port 1515(local) to 8082(remote) and I need to send the message from port 8082(local) to 8082(remote).
Thanks.

You need to bind the UdpClient to a local port before you call Send(). The only way to specify the source port is in the UdpClient's constructor, so if you do not know which source port to use until you have received a message first then you will have to wait until then before creating the UdpClient.
Private Sub UdpSend(ByVal txtMessage As String)
Dim pRet As Integer
Dim MyUdpClient as UdpClient = new UdpClient(8082); ' <-- here
MyUdpClient.Connect(IPAddress.Parse(IpRemotaLbl.Text), RemotePortLbl.Text)
bytCommand = Encoding.ASCII.GetBytes(txtMessage)
pRet = MyUdpClient.Send(bytCommand, bytCommand.Length)
'Console.WriteLine("No of bytes send " & pRet)
PrintLog("No of bytes send " & pRet)
End Sub

Related

TCP Listener connection is closed before acknowledgement/response can be sent

I am writing a TCP listener (server) that needs to receive messages and send back an acknowledgement. Pretty basic stuff. There are literally dozens of examples out there, including MSDN, from which I copied much of my code. I can receive the message no problem. The problem comes when I try to send back the response. The sending client (Corepoint HL7 engine) reports the following error:
The connection was closed before a response was received
I have tested my service with my own TCP sending test app (written using code copied from MSDN) and it works. But when I receive messages from Corepoint, the response does not go back.
Below is my code. Does anyone have any idea why the NetworkStream.Write method is not actually sending the data (or why the client is not receiving it)? I've tried every idea I've found in other posts that are similar to my problem, and nothing is working. Am I doing something wrong, or is something wrong in the configuration of Corepoint?
Sub Main()
listenThread.Start()
End Sub
Private serverSocket As TcpListener
Dim listenThread As New Thread(New ThreadStart(AddressOf ListenForClients))
Private Sub ListenForClients()
Dim port As Int32 = '(pick a port #)
Dim localIP As IPAddress = 'enter your IP
serverSocket = New TcpListener(localIP, port)
serverSocket.Start()
While True 'blocks until a client has connected to the server
Dim client As TcpClient
If serverSocket.Pending Then
client = serverSocket.AcceptTcpClient
'tried these 2 settings with no effect
'client.NoDelay = True
client.Client.NoDelay = True
ProcessIncomingMessageSocketTCPClient(client) 'I was doing this in a separate thread but temporarily kept it on this thread to eliminate threading as the possible cause (but no luck)
client.Close()
Else
Threading.Thread.Sleep(1000) 'wait 1 second and poll again
End If
End While
End Sub
Private Sub ProcessIncomingMessageSocketTCPClient(ByRef objClient As TcpClient)
Dim strMessageText As String
Dim clientStream As NetworkStream
Dim msgBuffer(4096) As Byte
Dim numberOfBytesRead As Integer
Dim strChunk As String
Dim strCompleteMessage As New Text.StringBuilder
Dim sendBytes As Byte()
clientStream = objClient.GetStream()
Do
numberOfBytesRead = clientStream.Read(msgBuffer, 0, msgBuffer.Length)
strChunk = Encoding.ASCII.GetString(msgBuffer, 0, numberOfBytesRead)
strCompleteMessage.AppendFormat("{0}", strChunk)
Loop While clientStream.DataAvailable
strMessageText = strCompleteMessage.ToString
sendBytes = Encoding.ASCII.GetBytes("I received a message from you")
clientStream.Write(sendBytes, 0, sendBytes.Length)
objClient.Close() 'tried it with and without this line
End Sub
It turns out that nothing is wrong with my code. The TCP was and is working correctly. This application is an HL7 listener and I was missing the MLP wrapping around my ACK. As soon as I added that, the sending application accepted my ACK and all is good.

Com Port doesn't work unless Hyperterminal Open and Closes Port First

So I am trying to connect to a piece of hardware. If I connect and disconnect with hyperterminal first. Then close the connection and the program. Everything works fine. If I don't I receive random characters back from the hardware. I use the same settings in hyperterminal as I do in the code.
baud=9600
parity=n
data=8
stop=1
Hardware flow controls "ON":
octs=on to=on dtr=on rts=hs
If I then disconnect the hardware and the serial port I will have the same problem again.
Is there anyway I can see how to comport is being configured after hyperterminal open and closes the port? I should note I am using a prolific serial to USB adapter.
Below is the code I use to open the com port.
Function OpenCom(PortNum As Integer, Baud As Long) As Long
Dim lpDCB As DCB
Dim ComTimeout As COMMTIMEOUTS
com$ = "COM" + Trim(Str(PortNum))
'open the communications port
hcomtemp& = CreateFile(com$, GENERIC_READ Or GENERIC_WRITE, 0, ByVal 0, OPEN_EXISTING, 0, ByVal 0)
'check for errors
If hcomtemp& < 0 Then
OpenCom = hcomtemp&
Exit Function
End If
r& = PurgeComm(hcomtemp&, 12) ' purge the comm RX and TX (RXCLEAR=0x08 and TXCLEAR=0x04)
' COMMAND LINE for "Hardware" flow control - mode com: baud=9600 parity=n data=8 stop=1 octs=on to=on dtr=on rts=hs
Build$ = "baud=" + Trim(str(Baud)) + " parity=N data=8 stop=1 octs=on to=on dtr=on rts=hs"
'build the data communications block
r& = BuildCommDCB(Build$, lpDCB)
'set the communications port's parameters with the DCB
r& = SetCommState(hcomtemp&, lpDCB)
ComTimeout.ReadIntervalTimeout = 100 'maximum time to wait between received bytes (milliseconds)
ComTimeout.ReadTotalTimeoutConstant = 1000 'maximum time to wait for receive data (milliseconds)
'set the timeouts
r& = SetCommTimeouts(hcomtemp&, ComTimeout)
'set the input buffer size to 4096 bytes and the output buffer size to 4096 bytes
r& = SetupComm(hcomtemp&, 4096, 4096)
'return the handle of the newly opened communications port
OpenCom = hcomtemp&
End Function
Please, try Advanced Serial Port Monitor -> Spy mode. http://www.aggsoft.com/serial-port-monitor.htm. It will show all actions that Hyperterminal does on the port. Then you can repeat these settings. It seems that the problem is related with the hardware flow control settings.
Below is the code I used to fix my problem. I only ever had to do it this way for one piece of equipment.
Function HandShakeBM5AS(ComPort As Integer) As Boolean
Dim Bm5ACom As Long
Dim x As Variant
Dim Path As String
comm$ = ComPort
Commands$ = "MODE COM" & comm$ & ": BAUD=9600 PARITY=N DATA=8 STOP=1 TO=ON XON=OFF ODSR=OFF OCTS=ON DTR=ON RTS=HS IDSR=OFF"
Call Shell("cmd.exe /S /C" & Commands$, vbNormalFocus)
'Shell (Commands$)
End Function
BuildCommDCB() fails if 'rts=hs' is included in the control string. This causes lpDCB to be not set correctly, and SetCommState is called with the wrong values.
You can set the RTS control flag in the lpDCB structure after calling BuildCommDCB. (I would include code but I'm not certain on the Basic syntax)

Find serial port where my device is connected

I'm starting to work with a pinpad.
I need that my program find the port where the pinpad is connected without user interaction.
I tried with:
Dim searcher As New ManagementObjectSearcher("root\cimv2","SELECT * FROM Win32_SerialPort")
For Each queryObj As ManagementObject In searcher.Get()
MsgBox(queryObj("Name"))
Next
but this only give me "COM1" and "COM2" as an answer (My device is connected to COM4)
and with
Dim searcher As New ManagementObjectSearcher("root\cimv2", "SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0")
For Each queryObj As ManagementObject In searcher.Get()
MsgBox(queryObj("Name"))
Next
With this one I can see my device friendly name but I donĀ“t know how to get the port (I receive the names like 'HP printer')
Any idea of how can I get the port that I need?
Thanks in advance
Based on the comments it sounds like your device is a USB device that has a driver that causes it to appear to be (emulates) a serial port attached device. In that case I would use:
My.Computer.Ports.SerialPortNames
to enumerate and loop over all serial ports. Then, one at a time try to open each one and send a command to the device that you know it responds to. Most devices have some kind of heartbeat or keep alive message that they will respond to. Whichever port you get a response on is the port you need to use.
I want to point 2 matters:
1: here is a solution i used for this problem (efficiancy corrections will be appreciated)
I used this soution i used to figure out on which port vx805 verifone pin pad was connected (has a unique device id):
Friend Class pinPadComLocater
Private Shared com As String
Private Const PNPDeviceID = "VID_11CA&PID_0220"
Private Const scope = "root\cimv2"
Public ReadOnly pinPadCom As String = Nothing
Sub New()
If isVX805PinPadConnected() Then
pinPadCom = com
Output.mainLog(Output.pinpadLocationMsg + com)
Else
Output.mainLog(Output.pinpadNotFoundMsg)
End If
End Sub
Private Shared Function queryCom(port As String) As Boolean
Dim query = "SELECT * FROM Win32_PnPEntity WHERE ClassGuid=""{4d36e978-e325-11ce-bfc1-08002be10318}"" AND DeviceID LIKE ""%" + PNPDeviceID + "%"" AND Caption LIKE ""%" + port + "%"""
Dim resp = New ManagementObjectSearcher(scope, query).Get
If resp.Count = 1 Then Return True
For Each queryObj As ManagementObject In resp
For Each prop In queryObj.Properties 'print all data for development purposes
Try
Console.writeline(prop.Name + " : " + queryObj(prop.Name).ToString)
catch ex As Exception
End Try
Next
Next
Return False
End Function
Private Shared Function isVX805PinPadConnected() As Boolean
For Each port In My.Computer.Ports.SerialPortNames
Try
If queryCom(port) Then
com = port
Return True
End If
Catch err As ManagementException
Throw New ConstraintException("An error occurred while querying for WMI data: " & err.Message)
End Try
Next
Throw New ConstraintException("Pin Pad Com Port could not be located")
Return False
End Function
End Class
2: would love more clarifiaction on that:
Then, one at a time try to open each one and send a command to the device that you know it responds to. Most devices have some kind of heartbeat or keep alive message that they will respond to
I would love to see a code example of how you send such a heartbeat check to a pinpad

USB COM port data reading error

I am using people count device to read the InCount, Out Count record and it is connected with my PC COM3 USB port.. I have written the code to fetch the data, I am continuously receiving the below message while reading the data..... can I have some code or idea to fetch the record?
message is.... The operation has timed out.
mycode is below:
Function ReceiveSerialData() As String
' Receive strings from a serial port.
Dim returnStr As String = ""
Dim com1 As IO.Ports.SerialPort
'SerialPort sp = new SerialPort("COM3", 115200, Parity.None, 8, StopBits.One);
Try
com1 = My.Computer.Ports.OpenSerialPort("COM3")
com1.BaudRate = 115200
com1.ReadTimeout = 10000
Do
Dim Incoming As String = com1.ReadLine()
If Incoming Is Nothing Then
Exit Do
Else
returnStr &= Incoming & vbCrLf
End If
Loop
Catch ex As TimeoutException
returnStr = "Error: Serial Port read timed out."
Finally
If com1 IsNot Nothing Then com1.Close()
End Try
Return returnStr
End Function
You must know at least the following 7 parameter settings for the device you are trying to communicate with and set your serial port properties to match.
PortName
BaudRate
Parity
DataBits
StopBits
NewLine
Handshake
Some of these you might guess (Parity is usually none, Databits is usually 8 stop bits is usually 1, handshake is often none). But Hans is correct unless you get all these set properly you will never communicate with your device. Also it is better to open your serial port once during initialization of your program and then leave it open until the program closes.

TCP Server in VB.NET

I am not a software programmer but I have a task to create a TCP Server (a program that is listening on its network card interfaces for incoming data streams).
I have searched on the internet and I found that I can use two methods: Socket or TCPListener class.
I have created an example for the Socket class, but I was wondering how I can test it?
If another computer in the network sends some string data to the listener computer, then the message should be displayed.
Here is the example from Microsoft that I am using for the TCP server using a Socket:
Public Shared Sub Main()
' Data buffer for incoming data.
Dim data = nothing
Dim bytes() As Byte = New [Byte](1024) {}
Dim ipAddress As IPAddress = ipAddress.Any
Dim localEndPoint As New IPEndPoint(ipAddress, 0)
Dim intI As Integer = 0
'Display the NIC interfaces from the listener
For Each ipAddress In ipHostInfo.AddressList
Console.WriteLine("The NIC are {0}", ipHostInfo.AddressList(intI))
intI += 1
Next
Console.WriteLine("You are listening on {0}",localEndPoint)
' Create a TCP/IP socket.
Dim listener As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
' Bind the socket to the local endpoint and
' listen for incoming connections.
Try
listener.Bind(localEndPoint)
listener.Listen(200)
Catch e As SocketException
Console.WriteLine("An application is alreading using that combination of ip adress/port", e.ErrorCode.ToString)
End Try
' Start listening for connections.
While True
Console.WriteLine("Waiting for a connection...")
' Program is suspended while waiting for an incoming connection.
Dim handler As Socket = listener.Accept()
data = Nothing
' An incoming connection needs to be processed.
While True
bytes = New Byte(1024) {}
Dim bytesRec As Integer = handler.Receive(bytes)
data += Encoding.ASCII.GetString(bytes, 0, bytesRec)
Console.WriteLine("The string captured is {0}", data)
If data.IndexOf("something") > -1 Then
Exit While
End If
End While
' Show the data on the console.
Console.WriteLine("Text received : {0}", data)
' Echo the data back to the client.
Dim msg As Byte() = Encoding.ASCII.GetBytes(data)
handler.Shutdown(SocketShutdown.Both)
handler.Close()
End While
End Sub
End Class
Am I on the right lead?
Thanks
Later Edit:
I have used that code in a Console Application created with Visual Studio and I want to check the scenario when a device is sending some string message through the network.
E.g:
I have two devices :Computer A, computer B connected through LAN
I have tried this command : telnet computerA port ( from computer B) but nothing is displayed in the TCP server running from computer A.
telnet 192.168.0.150 3232
I also made a TCP client for testing (derived from the Microsoft example):
Public Class SynchronousSocketClient
Public Shared Sub Main()
' Data buffer for incoming data.
Dim bytes(1024) As Byte
Dim ipHostInfo As IPHostEntry = Dns.GetHostEntry(Dns.GetHostName())
Dim ipAddress As IPAddress = ipHostInfo.AddressList(0)
Dim remoteEP As New IPEndPoint(ipAddress, 11000)
' Create a TCP/IP socket.
Dim sender As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
' Connect the socket to the remote endpoint.
sender.Connect(remoteEP)
Console.WriteLine("Socket connected to {0}", _
sender.RemoteEndPoint.ToString())
' Encode the data string into a byte array.
Dim msg As Byte() = _
Encoding.ASCII.GetBytes("This is a test<EOF>")
' Send the data through the socket.
Dim bytesSent As Integer = sender.Send(msg)
' Receive the response from the remote device.
Dim bytesRec As Integer = sender.Receive(bytes)
Console.WriteLine("Echoed test = {0}", _
Encoding.ASCII.GetString(bytes, 0, bytesRec))
' Release the socket.
sender.Shutdown(SocketShutdown.Both)
sender.Close()
Console.ReadLine()
End Sub
End Class 'SynchronousSocketClient
But it does not work because of the PORT setting.
If in the TCP Server I have "Dim localEndPoint As New IPEndPoint(ipAddress, 0)" then the client crashes, but if I change the port from any (0) to 11000 for example, the client works fine.
Do you know why?
Later edit 2:
Maybe I should have started with this question: Which method is recommended for my scope - asynchronous or synchronous method?
Yes, you are on the right path.
The next thing to do is to introduce message detection since TCP is stream based and not message based like UDP. This means that TCP might decide to send two of your messages in the same packet (so that one socket.Recieve will get two messages) or that it will split up your message into two packets (thus requiring you to use two socket.Recieve to get it).
The two most common ways to create message detection is:
Create a fixed size header which includes message size
Create a delimiter which is appended to all messages.
Your "server" isn't listening on a set port, so you'll need to pay attention to the "You are listening on" message that appears. Then, from another machine on the network, telnet the.ip.add.ress port. (This may require installing "telnet client", or enabling it in the Programs and Features stuff, or whatever.)
Side note...if you actually intend for this to be a server of some sort, you'll want to decide what port you want to use, so that other computers can find your service. Most people won't be able to read your screen to figure out where to connect. :)
As for your "client"...when you connect to another computer, you don't just "pick a port" (which is what a port number of 0 means in an endpoint). You need to know what port the server uses. (Reread what i said in the previous paragraph. A program running on another computer has no idea what port to use to connect to the server -- any server could be running on any port.) You need to pick a port number for the server (say, 11000...good as any, really) rather than letting it use port 0.