redspidermkv
redspidermkv

Reputation: 541

TcpClient socket - only one usage of each socket address exception

I'm at a bit of a loss with this exception being thrown when using TcpClient and TcpListener. It works the first time, I then run it again and I get the following exception:

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

I've checked to make sure I was closing any open connections. I've tried manually calling close on the TcpClient as well as using the IDisposable using pattern but still have the same problem.

Here's the code, it should just run if you copy paste it in Visual Studio (provided you've added the following using statements)

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

internal class Program
{
    private static void tcpClientConnection()
    {
        Console.WriteLine("Ready");
        Console.ReadKey();

        IPAddress address = IPAddress.Parse("127.0.0.1");

        using (TcpClient client = new TcpClient(new IPEndPoint(address, 8087)))
        {
            client.Connect(new IPEndPoint(address, 8086));

            using (NetworkStream ns = client.GetStream())
            {
                ns.Write(System.Text.Encoding.ASCII.GetBytes("Hello"), 0, "Hello".Length);
                ns.Flush();
            }

            Console.WriteLine("Closing client");
        }
    }

    internal static void Main(string[] args)
    {
        IPAddress address = IPAddress.Parse("127.0.0.1");

        TcpListener server = new TcpListener(new IPEndPoint(address, 8086));
        server.Start();

        using (Task task2 = new Task(tcpClientConnection))
        {
            task2.Start();

            using (TcpClient client = server.AcceptTcpClient())
            {
                using (NetworkStream ns = client.GetStream())
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        ns.CopyTo(ms);
                        byte[] data = ms.ToArray();

                        Console.WriteLine(System.Text.Encoding.ASCII.GetString(data));
                    }
                }
            }

            Console.WriteLine("Server stop");
            Console.ReadKey();

            server.Stop();
        }

        Console.WriteLine("END");
        Console.ReadKey();

    }
}

Please note, I've looked at the solutions offered in similar questions but haven't been able to see what the problem is...

Upvotes: 4

Views: 3979

Answers (2)

uncaged
uncaged

Reputation: 797

I've found a couple of settings that seem to greatly reduce (but not completely eliminate) getting this error when reusing a socket that has its local endpoint specified:

tcpClient.Client.SetSocketOption( SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true );
tcpClient.LingerState = new LingerOption( true, 0 );

I should probably also mention that before closing the tcpClient, I'm closing the client's stream and doing:

if ( tcpClient.Client.Connected )
    tcpClient.Client.Shutdown( SocketShutdown.Both );

This might help, but if anyone figures out something that completely prevents getting this error, please share.

Upvotes: 0

usr
usr

Reputation: 171178

For the TcpClient don't specify the local endpoint. I think that fixes the problem and you should not do that anyway because it accomplishes nothing. specifying the local endpoint for outgoing connections makes the OS select appropriate and available values. Normally, 99.9% of all programs are doing this.

Some programs need to specify the local endpoint in order to only listen on certain IPs or interfaces. It seems you don't need that.

If all the connections are being closed, should it not be ok to continue using the same address and port?

TCP has some unintuitive behavior that causes connections to hang around for a while after they have been closed. By letting the OS select you a fresh port that problem is mitigated.

You also might want to look into usage of Task and pick up some best practices: Use Task.Run and don't dispose. It's pointless.

Upvotes: 3

Related Questions