Search code examples
vb.netsocketstcpzebra-printers

"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


Solution

  • 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"