1
votes

I have a TCP server (implemented as a windows service) for listening to GPS devices in a vehicle tracking application, after random period of time from its operation I got the following error : "Only one usage of each socket address (protocol/network address/port) is normally permitted." While I am sure that I am closing every socket after using it. so can anyone tell me what is the problem here I have the MaxUserPort value in windows server 2008 registry with (65534) and the TCPTimeWaitDelay value with (30 seconds) ?

Here is the code: 1) The Main Thread :

 private void MainThread() {
        byte[] bytes = new Byte[1024];

        IPEndPoint localEndPoint = new IPEndPoint(0, this.port);

        Socket listener = new Socket(AddressFamily.InterNetwork,
            SocketType.Stream, ProtocolType.Tcp );
        // Addedd on [20/03/2012] by Sherif Mosaad for handling socket exceptions ...
        //listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, (int)1);

        try {
            listener.Bind(localEndPoint);
            listener.Listen(100);

            while (active) {
                mainDone.Reset();

                listener.BeginAccept(new AsyncCallback(AcceptCallback),listener);

                while (active)
                    if (mainDone.WaitOne(100, true))
                        break;
            }
            listener.Shutdown(SocketShutdown.Both);
            listener.Close();
            Thread.Sleep(2000);

        } catch (Exception e) {
            if (OnError != null)
                OnError(this, e.ToString());
            LogManager.LogError(e, "TCPSimpleServer MainThread"); 
        }
    }

2) The AcceptCallback handler:

private void AcceptCallback(IAsyncResult ar) {
        mainDone.Set();

        Socket listener = (Socket)ar.AsyncState;
        Socket handler = null;
        try
        {
            handler = listener.EndAccept(ar);
        }
        catch 
        {
            try
            {
                listener.Shutdown(SocketShutdown.Both);
                listener.Close();
                Thread.Sleep(2000);
            }
            catch { return; }
        }

        if (OnConnect != null)
            OnConnect(this, handler);

        StateObject state = new StateObject();

        state.workSocket = handler;
        state.endPoint = (IPEndPoint)handler.RemoteEndPoint;
        stateObjectDictionary.Add(state, state.workSocket);
        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
            new AsyncCallback(ReadCallback), state);
    }

3) The ReadCallback Handler:

 private void ReadCallback(IAsyncResult ar) {
        String content = String.Empty;
        StateObject state = (StateObject)ar.AsyncState;
        Socket handler = state.workSocket;

        int bytesRead = 0;
        try
        {
            bytesRead = handler.EndReceive(ar);
        }
        catch (Exception e)
        {
            // Connection closed by client
            if (OnDisconnect != null)
                OnDisconnect(this, state.endPoint);
            return;
        }

        if (bytesRead > 0)
        {
            string data = Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
            if (OnDataAvailable != null)
                OnDataAvailable(this, handler, data);
            try
            {
                handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReadCallback), state);
            }
            catch (Exception e)
            {
                // Connection closed by client
                if (OnDisconnect != null)
                    OnDisconnect(this, state.endPoint);
                return;
            }
        }
        else
        {
            // Connection closed by peer
            if (OnDisconnect != null)
                OnDisconnect(this, state.endPoint);
        }
    }

Finally the state object :

public class StateObject
    {
        public Socket workSocket = null;
        public const int BufferSize = 1024;
        public byte[] buffer = new byte[BufferSize];
        public StringBuilder sb = new StringBuilder();
        public IPEndPoint endPoint;
    }

Any help please?

1
Does it happen to occur after an exception in your first block of code? You should probably be cleaning up your listener in a finally block rather than inside the try itself.M.Babcock

1 Answers

0
votes

There's a race condition. You call mainDone.Set which allows another thread to proceed to BeginAccept while the current thread moves towards EndAccept. Which will get there first? If you start accepting before finishing the previous accept, I suspect this error might pop up.

Fix? You need to set mainDone event after you call EndAccept

Even better, follow a simpler pattern without synchronization primitives. I outline one here.