6

I'm trying to implement async sockets for my project. Here's the code

    public void Start(int listeningPort)
    {
        var ipHostInfo = Dns.Resolve(Dns.GetHostName());
        var ipAddress = ipHostInfo.AddressList[0];
        var localEndPoint = new IPEndPoint(ipAddress, listeningPort);

        _listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        _listener.Bind(localEndPoint);
        _listener.Listen(3000);
        Started = true;

        Task.Factory.StartNew(() =>
        {
            while (Started)
            {
                allDone.Reset();

                _listener.BeginAccept(AcceptCallback, _listener);

                allDone.WaitOne();
            }
        });
    }

    public void Stop()
    {
        Started = false;
        _listener.Shutdown(SocketShutdown.Both); //<-- throws SocketException
        _listener.Close(2000);
        _listener = null;
    }

    public void Kick(IClient client)
    {
        try
        {
            Clients.Remove(client);
            client.Socket.Shutdown(SocketShutdown.Both);
            client.Socket.Close();
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
    }

    private void AcceptCallback(IAsyncResult ar)
    {
        Socket handler = null;
        try
        {
            allDone.Set();

            var listener = (Socket) ar.AsyncState;
            handler = listener.EndAccept(ar);

            var client = new Client(this, handler);
            Clients.Add(client);

            var state = new StateObject();
            state.Socket = handler;
            handler.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0, ReadCallback, state);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
            var client = ClientBySocket(handler);
            if(handler != null && client != null) Kick(client);
        }
    }

    private void ReadCallback(IAsyncResult ar)
    {
        Socket handler = null;
        try
        {
            var state = (StateObject) ar.AsyncState;
            handler = state.Socket;

            var bytesRead = handler.EndReceive(ar);
            if (bytesRead > 0)
            {
                if (Received != null)
                {
                    var buff = new byte[bytesRead];
                    if (buff[0] == 0)
                    {
                        Stop();
                    }
                    return;
                    Array.Copy(state.Buffer, buff, bytesRead);
                    Debug.WriteLine(Encoding.UTF8.GetString(buff));
                    try
                    {
                        Received(this, new ReceiveArgs(buff));
                    }
                    catch(Exception ex)
                    {
                        Debug.WriteLine(ex.Message);
                    }
                }
            }
            handler.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0, ReadCallback, state);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
            var client = ClientBySocket(handler);
            if (handler != null && client != null) Kick(client);
        }
    }

but everytime I call Stop (which in turn, calls shutdown) (no matter clients are connected or not), Socket.Shutdown throws SocketException with message

Additional information: A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied

I'm really stuck here. Anyone knows what I'm doing wrong?

Davita
  • 8,928
  • 14
  • 67
  • 119

1 Answers1

10

Your listening socket is not connected. I think the message says this quite well. Everytime you accept a connection you get a new socket that is independent. The original socket is never connected to anything.

Just don't call Shutdown on it.

Btw, your Accept loop is using async IO, then waiting for it to complete. That makes no sense. Use the synchronous version.

usr
  • 168,620
  • 35
  • 240
  • 369
  • 1. But how should I stop server socket? Should I shutdown every socket individually (except the listener)? 2. About async IO. Would it be better if I called BeginAccept after EndAccept? In that case I woulnd't need ManualResetEvent right? – Davita May 30 '14 at 21:23
  • 1. Just close the listener. It is independent of all other sockets. What is Shutdown supposed to on on a non-connected socket?! There is not data to send or receive. 2. You can pick: Either async IO without waiting, or synchronous IO. Mixtures rarely make sense. I recommend to use sync IO wherever possible because it is far easier to program and debug. If you have to ask you should probably go synchronous. – usr May 30 '14 at 21:48