1

I'm trying to connect to a TCP server with .NET's TcpClient. For testing, the server is on my own machine. It worked initially, but not when I restarted my application.

So I wrote this small bit of code to try connect/disconnect twice and I can't figure out what I'm doing wrong:

const int clientPort = 29501;
const int port = 29500;

using (var client = new TcpClient(new IPEndPoint(IPAddress.Loopback, clientPort)))
    client.Connect(IPAddress.Loopback, port);

using (var client = new TcpClient(new IPEndPoint(IPAddress.Loopback, clientPort)))
    client.Connect(IPAddress.Loopback, port);

When I run this code, i get a SocketException:

Only one usage of each socket address (protocol/network address/port) is normally permitted

What am I doing wrong? Shouldn't the using blocks properly release the socket?

relatively_random
  • 4,505
  • 1
  • 26
  • 48
  • 2
    Your local connections cannot share the same **local** port. –  Aug 07 '17 at 14:23
  • @Amy But `using` should disconnect the last connection from that port before the new one starts, right? – relatively_random Aug 07 '17 at 14:27
  • `Dispose()` just tells the GC that the object is available for collection. It does not immediately force garbage collection, hence it doesn't immediately cause the connection to be closed. –  Aug 07 '17 at 14:29
  • Have a look at [`LingerState`](https://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.lingerstate(v=vs.110).aspx), it's possible your connection may be remaining open after `Close` is called. I'll also just point out that you don't *have* to specify an endpoint for the client to bind to - you can leave it out and [one will be generated for you](https://msdn.microsoft.com/en-us/library/zc1d0e0f(v=vs.110).aspx), so unless you actually need to bind both clients to the same port, it's safer to let the system allocate you a free port. – hnefatl Aug 07 '17 at 14:32
  • @Amy Garbage collection shouldn't matter here. Dispose exists precisely so you can clean something up immediately, without waiting for garbage collector and finalizer to kick in. – relatively_random Aug 07 '17 at 14:36
  • @hnefatl Tried it just now. `LingerState = new LingerOption(false, 0)` doesn't help. – relatively_random Aug 07 '17 at 14:38
  • 1
    **Why** are you doing this? Why do you want to connect from a specific client port? The port will be in wait state after use anyway, see duplicate. You can't do this, other than to configure the TIME_WAIT interval to a very low value ([which you don't want to](https://stackoverflow.com/questions/3757289/tcp-option-so-linger-zero-when-its-required)), or by asking the OS's TCP/IP stack to do its job and assign you a free client port. – CodeCaster Aug 07 '17 at 14:39
  • @relatively_random You would need to set `Enabled` to `true`, not `false`. – hnefatl Aug 07 '17 at 14:41
  • @hnefatl My mistake. Still doesn't work, though. – relatively_random Aug 07 '17 at 14:44
  • @relatively_random No, it won't work for the reason described in the duplicate. With a bit of poking you could have found [this link](https://stackoverflow.com/questions/2698999/how-to-reuse-socket-in-net) from the dupe, which provides some more things you could try. – hnefatl Aug 07 '17 at 14:50

1 Answers1

1

As you can see in MSDN using constructor with parameter of type IPEndPoint also binds to that specified port. In your case you don't need clients to bind to another ports, only server socket must be bound to a TCP port.

So you can use parameterless constructor instead:

const int port = 29500;

using (var client = new TcpClient())
    client.Connect(IPAddress.Loopback, port);

using (var client = new TcpClient())
    client.Connect(IPAddress.Loopback, port);
vasek
  • 2,759
  • 1
  • 26
  • 30