VB 2010 Kill thread by name - vb.net

In my multi-threading server app, a thread per client is generated in this way:
While (True)
counter += 1
clientSocket = serverSocket.AcceptTcpClient()
log.debug("Client No: " + Convert.ToString(counter) + " started!")
Dim client As New handleClinet
clients.Add(clientSocket)
client.startClient(clientSocket, Convert.ToString(counter))
End While
and in handleClinet:
Public Sub startClient(ByVal inClientSocket As TcpClient, ByVal clineNo As String)
Me.clientSocket = inClientSocket
Me.clNo = clineNo
Dim ctThread As Threading.Thread = New Threading.Thread(AddressOf doChat)
ctThread.Name = "client" + clineNo
ctThread.Start()
End Sub
As you can see, the thread is made with the name client1, client2, etc. When a user signs out, a command is send to the server along with the clientID. But how can I kill the specific client process?
Something like:
Public Sub killClient(ByVal clientID As Int32)
'Code to kill "client"+clientID
End Sub

Threads are just execution vehicles. Any time you think you need to push a thread around, think instead about what the thread is doing. When you don't need your doctor anymore, you don't kill him. You leave his office.
If you want to shut down the client cleanly, set a 'shutdown' flag in the client structure. Have the code that handles the client check this flag periodically. Forget about what thread is doing it, it's the client you want to shut down.
If that's too passive, shutdown the TCP connection to the client. That will cause any code that touches the client's connection to get an error.
Forget about the fact that it happens to be a dedicated thread that's handling the client. You wrote the code. Code it so that it stops handling the client when that's no longer appropriate by checking if it's appropriate to handle a client before handling it.

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.

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

Already running application now gets socket error 10013

I have an application done in VB.NET that listen on a specific UDP port and answer through the same port to the IP that send the packet.
It was working ok from a couple of years to the last month; now when try to answer crash due to socket error 10013.
I even try an older version that I know it was working too and get the same crash.
I try disabling Microsoft Security Essentials real time protection and Windows firewall and didn't work.
In the code I have the line
MyUdpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, True)
I have no clue about what to do, I'm lost.
Any idea how to solve this?
Edit:
Here's the code
#Region "UDP Send variables"
Dim GLOIP As IPAddress
Dim GLOINTPORT As Integer
Dim bytCommand As Byte() = New Byte() {}
#End Region
Dim MyUdpClient As New UdpClient()
Private Sub StartUdpBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles StartUdpBtn.Click
If StartUdpBtn.Tag = 0 Then
' If Not UdpOpen Then
StartUdpReceiveThread(CInt(ListeningPortLbl.Text))
'End If
Else
If ThreadReceive.IsAlive Then
ThreadReceive.Abort()
MyUdpClient.Close()
PrintLog("UDP port closed")
StartUdpBtn.Tag = 0
UdpOpen = False
StartUdpBtn.Text = "Start UDP"
End If
End If
If UdpOpen Then
StartUdpBtn.Tag = 1
StartUdpBtn.Text = "Stop UDP"
Else
StartUdpBtn.Tag = 0
StartUdpBtn.Text = "Start UDP"
TimerUDP.Enabled = False
TiempoUDP.Stop()
TiempoUdpLbl.Text = "--:--:--"
End If
End Sub
Private Sub StartUdpReceiveThread(ByVal Port As Integer)
Dim UdpAlreadyOpen As Boolean = False
Try
If Not UdpOpen Then
MyUdpClient = New UdpClient(Port)
MyUdpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, True)
UdpAlreadyOpen = True
Else
Me.Invoke(Sub()
TiempoUDP.Restart()
If TimerUDP.Enabled = False Then
TimerUDP.Enabled = True
End If
End Sub)
End If
ThreadReceive = New System.Threading.Thread(AddressOf UdpReceive)
ThreadReceive.IsBackground = True
ThreadReceive.Start()
UdpOpen = True
If UdpAlreadyOpen Then
PrintLog(String.Format("UDP port {0} opened, waiting data...", Port.ToString))
End If
Catch ex As Exception
PrintErrorLog(ex.Message)
PrintErrorLog(ex.StackTrace)
End Try
End Sub
Private Sub UdpReceive()
Dim receiveBytes As [Byte]() = MyUdpClient.Receive(RemoteIpEndPoint)
DstPort = RemoteIpEndPoint.Port
IpRemota(RemoteIpEndPoint.Address.ToString)
Dim BitDet As BitArray
BitDet = New BitArray(receiveBytes)
Dim strReturnData As String = System.Text.Encoding.ASCII.GetString(receiveBytes)
If UdpOpen Then
StartUdpReceiveThread(CInt(ListeningPortLbl.Text))
End If
PrintLog("From: " & RemoteIpLbl.Text & ":" & ListeningPortLbl.Text & " - " & strReturnData)
AnswersProcessor(strReturnData)
End Sub
Private Sub UdpSend(ByVal txtMessage As String)
Dim pRet As Integer
GLOIP = IPAddress.Parse(RemoteIpLbl.Text)
'From UDP_Server3_StackOv
Using UdpSender As New System.Net.Sockets.UdpClient()
Dim RemoteEndPoint = New System.Net.IPEndPoint(0, My.Settings.UDP_Port)
UdpSender.ExclusiveAddressUse = False
UdpSender.Client.SetSocketOption(Net.Sockets.SocketOptionLevel.Socket, Net.Sockets.SocketOptionName.ReuseAddress, True)
UdpSender.Client.Bind(RemoteEndPoint)
UdpSender.Connect(GLOIP, DstPort)
bytCommand = Encoding.ASCII.GetBytes(txtMessage)
pRet = UdpSender.Send(bytCommand, bytCommand.Length)
End Using
PrintLog("No of bytes send " & pRet)
End Sub
10013 is WSAEACCES, which is documented as follows:
Permission denied.
An attempt was made to access a socket in a way forbidden by its access permissions. An example is using a broadcast address for sendto without broadcast permission being set using setsockopt(SO_BROADCAST).
Another possible reason for the WSAEACCES error is that when the bind function is called (on Windows NT 4.0 with SP4 and later), another application, service, or kernel mode driver is bound to the same address with exclusive access. Such exclusive access is a new feature of Windows NT 4.0 with SP4 and later, and is implemented by using the SO_EXCLUSIVEADDRUSE option.
In the comments you mentioned:
I tried the program on a XP x32 and works ok but on Windows 7 x32/x64 don't, even if I disable the firewall and Microsoft Security Essentials Live Protection.
Maybe it sounds almost obvious but you could try to start your program in all of the available Windows XP compatibility modes. You didn't say that you already tried this but maybe you're lucky and the problem will be "solved" by this workaround.
If the problem still exists afterwards and considering the error code of 10013, I would try or check the following things:
I know you disabled "Microsoft Security Essentials" and the Windows Firewall, but double check whether there are other security related programs/services like anti virus protection, anti malware tools etc. running. It really sounds like something is blocking your socket creation/bind.
In case your program created log output/data which allows you to see exactly when it started to fail:
Any new software installed at that time?
Were Windows Updates (maybe automatically) installed at that time? Especially security updates regarding network security?
Any other noticeable changes in your environment? What about log entries in your Windows system log?
Just as a little test to verify if the error occurs only with your UDP socket: Try to use a TCP socket instead of UDP.
Start the machine in Windows Safe Mode with network support and execute your program from there.
Run your program on another Windows 7 machine and see if the same problem occurs there. It could be a valuable starting point (in terms of localization) to know if the problem occurs only on specific versions of Windows.
Single step through your code with a debugger and carefully watch what happens. Perhaps this can reveal some additional info on what's going wrong.
Maybe some of the ideas above can help you to track down the problem a little bit more. Good luck!

"KeepAlive" for TCPClient connection to keep connection open?

Is there a way to keep a TcpClient connection open constantly? I have an application which lets our users scan a carton, some database updates are performed, and a shipping label is sent to and printed from a wireless hip printer (model of printer is Zebra QLn420) which the user is using.
The application attempts to keep a connection to the wireless printer via the TcpClient connection, and multiple checks are made throughout processing to make sure the connection is good, before sending a generated ZPL to the printer for printing.
We have been having an issue with an occasional label missing, and it seems to be whenever the user stops scanning for a few minutes, then resumes. However, it is a semi-rare occurrence when a label is skipped, and as such is rather hard to reproduce (I haven't been able to replicate it myself, but I have seen it happen out in the warehouse).
I would like to know either if there is a way to make sure that the connection is always open (by "pinging" the device every so often), or if there is a way to get feedback that the data has been received and printed.
This is the code I'm calling to ensure a connection:
Public Function Connect(strIP As String, intPort As Integer) As Boolean
Try
'connect to printer via TcpClient, need ip address and port number
'connects without thread, hangs program for 10-20 seconds if printer is not turned on, replaced with code below to thread the connection and set timeout
For i As Integer = 1 To 2
If Not (client IsNot Nothing AndAlso client.Connected) Then
'uses ClientSocketParameters structure to pass to recursive function ConnectionReturned()
clntSockParams = New ClientSocketParameters
clntSockParams.addrs = strIP
clntSockParams.prt = intPort
'create client and call BeginConnect (attempts to connect on separate thread until TimeoutTime has elapsed)
client = New System.Net.Sockets.TcpClient
client.SendTimeout = 5000
client.ReceiveTimeout = 5000
'setup timer with timeout length and start, if timer goes past intTimeoutLength, the Timeout() function is called which closes everything and leaves client = Nothing
AddHandler TimeoutTime.Elapsed, AddressOf Timeout
TimeoutTime.Interval = intTimeoutLength
TimeoutTime.Start()
client.BeginConnect(strIP, intPort, New AsyncCallback(AddressOf ConnectionReturned), clntSockParams)
'keeps the program from doing anything else until BeginConnect either succeeds or fails (due to connect on separate thread)
Do While TimeoutTime.Enabled
System.Threading.Thread.Sleep(500)
Loop
End If
'if TimeoutTime is elapsed and client is Nothing, connection didn't happen, throw an error
If client Is Nothing Then
blnConnected = False
Else
blnConnected = True
Exit For
End If
Next
Catch ex As Exception
blnConnected = False
End Try
Return blnConnected
End Function
Private Sub ConnectionReturned(ByVal ar As System.IAsyncResult)
'this method is called from the client.BeginConnect line in Connect(), make sure timer is running
If TimeoutTime.Enabled Then
'ensure client is initialized
If client Is Nothing Then client = New System.Net.Sockets.TcpClient
'keep calling ConnectionReturned until client.Connected is true
If client.Connected Then
TimeoutTime.Stop()
Else
Dim actualParameters As ClientSocketParameters = DirectCast(ar.AsyncState, ClientSocketParameters)
client.BeginConnect(actualParameters.addrs, actualParameters.prt, New AsyncCallback(AddressOf ConnectionReturned), clntSockParams)
End If
End If
End Sub
Private Sub Timeout(ByVal sender As Object, ByVal e As EventArgs)
'this method is only called if TimeoutTime elapsed, which means no connection was made. close the client object if needed, set to Nothing, and stop TimeoutTime
If TimeoutTime.Enabled Then
Try
client.Close()
Catch ex As Exception
End Try
client = Nothing
TimeoutTime.Stop()
End If
End Sub
According to this question:
tcp client in vb.net not receiving the entire data response data from server
TcpClient is not always guaranteed to deliver all data to the other end of a connection, so if a more reliable connection method is available, that would be worth a try as well.
Please let me know if more information is needed. Thank you!
Originally I got the code for connecting via this link. I've modified it since because it would hang the application for 10-20 seconds if it took longer to connect. Code here is in C# and I translated to VB:
Send ZPL Commands via TCP/IP in C#
This is the link to the docs for the class:
TcpClient Class
Zebra printers have a timeout setting on TCP that I think has a 3 or 5 minute default. The first thing to do is to turn that timeout off. There will still be other reasons that the printer would disconnect so you will need to handle that as well.
embed this into your program:
! U1 setvar "wlan.ip.timeout.enable" "off"
Make sure you send a CR/LF before and after that line.
if you send a query after your format you can know that the whole format made it to the printer. Something like the following would work:
! U1 getvar "device.uptime"
That's not a sane solution. A sane solution is this: If a label isn't completely sent to the printer because the connection failed, make a new connection and send the label.

VB.NET/WMI - Real-Time Windows Service Monitoring?

So there's an application at my work that installs several Windows services to a server. As a side project, I've been asked to make a simple GUI that will list these services with a "light" (a picture box with a red or green dot) next to the name of each service. The idea is that in the event these services were to stop running, the "light" would change from green to red.
I have the GUI part built, and I can query a remote server's services, then compare it to an array of the ones I'm interested and set the "light" next to each service to green/red depending on the service state. The part I'm hung up on is how to monitor these services in real time? Currently, I just have the following code in the Form_Load event:
Dim myConnectionOptions As New System.Management.ConnectionOptions
With myConnectionOptions
.Impersonation = System.Management.ImpersonationLevel.Impersonate
.Authentication = System.Management.AuthenticationLevel.Packet
End With
Try
Dim myManagementScope As System.Management.ManagementScope
myManagementScope = New System.Management.ManagementScope("\\" & SERVERNAME & "\root\cimv2", myConnectionOptions)
myManagementScope.Connect()
Dim query As New Management.ObjectQuery("SELECT * FROM Win32_Service")
Dim searcher As New Management.ManagementObjectSearcher(myManagementScope, query)
Dim i As Integer = 0
For Each queryObj As Management.ManagementObject In searcher.Get()
For Each service As String In arrServices
If queryObj("DisplayName").Equals(service) Then
If queryObj("State").Equals("Stopped") Then
arrLights(i).Image = My.Resources.redlight
End If
i += 1
End If
Next
Next
Catch err As Management.ManagementException
MessageBox.Show("WMI query failed with the following error: " & err.Message)
Catch unauthorizedErr As System.UnauthorizedAccessException
MessageBox.Show("Authentication error: " & unauthorizedErr.Message)
End Try
Would a simple timer that executes this code repeatedly be the best approach, or is there a more elegant solution? I have a little experience in VB.NET and WMI, but none in any type of real-time monitoring activity like this.
First of all i would put it into a thread, that way even if your connection times out you dont freeze your UI, then i would use a custom wait timer not the built in one as cross threading can be a pain.
wait timer:
Public Sub Wait(ByVal wait_time As Integer)
Dim time As Date
time = Now.AddMilliseconds(wait_time)
Do While time > Now
Application.DoEvents()
Loop
End Sub
example of threading:
Private services_check As Thread
private sub form1_load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
services_check = new thread(AddressOf 'Current code in a public sub')
services_cheack.IsBackground = True
Services_check.start()
It may not be the most elegant solution but its how i would do it, as for your current code im sorry i dont know enough about remote connections to help you.