I think that the problem is that you are closing the form (server), which ends the thread where it runs, but that does not necessarily close the threads opened by it: when you close the application (with the X) it ends the main thread and any "background" thread, but this does not end the threads "in front" (Foreground Thread).
From the documentation we have:
Once all the foreground threads belonging to a process have terminated, the common language runtime ends the process. Any remaining background threads are stopped and do not complete
...
By default, the following threads execute in the foreground (that is, their IsBackground property returns false):
- The primary thread (or main application thread).
- All threads created by calling a Thread class constructor.
Solution:
The simplest thing is that when you create the thread you indicate that it is a "background" thread:
tcpThd = New Thread(AddressOf EsperarCliente)
tcpThd.IsBackground = True
tcpThd.Start()
In this way, when closing all the threads of front (in your case only one: the main one), all the threads of bottom will be closed immediately (the CLR is responsible for finishing them).
As an additional note: take into account that El Guille's article is 12 years old! not necessarily the most efficient / sure way to do what you want now (although it's fine if you're just practicing).