1

I need to write an app that accepts incoming sockect connections and sends some data to all off them every N ms. My code:

private readonly Timer _senderTimer;
private readonly Socket _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private readonly ConcurrentDictionary<EndPoint, Socket> _clientConnections =
            new ConcurrentDictionary<EndPoint, Socket>();

public Start(SettingsProvider settingsProvider)
{
    _senderTimer = new Timer(SendIntervalTick, null, settingsProvider.SendInterval, Timeout.Infinite);
    _serverSocket.Bind(new IPEndPoint(selfIp, selfPort));
    _serverSocket.Listen(MaxLengthOfPendingConnectionsQueue);
    _serverSocket.BeginAccept(AcceptCallback, null);
}

private void AcceptCallback(IAsyncResult result)
{
    EndPoint endPoint = null;
    try
    {
        var acceptedSocket = _serverSocket.EndAccept(result);
        endPoint = acceptedSocket.RemoteEndPoint;
        _clientConnections.TryAdd(endPoint, acceptedSocket);
    }
    catch (Exception e)
    {
        CloseSocket(endPoint);
    }
    finally
    {
        _serverSocket.BeginAccept(AcceptCallback, null);
    }
}

private void SendIntervalTick(object state)
{
    SendPacket(new[] {(byte)0xFF});
    _senderTimer.Change(Math.Max(0, _sendInterval - watch.ElapsedMilliseconds), Timeout.Infinite);
}

private void SendPacket(byte[] packet)
{
    var connToRemove = new List<EndPoint>();
    var connToSend = _clientConnections.ToDictionary(x => x.Key, x => x.Value);
    // Send packet to all connected clients
    foreach (var connection in connToSend)
    {
        try
        {
            connection.Value.BeginSend(packet, 0, packet.Length, 
                SocketFlags.None, 
                SendCallback, 
                new ClientConnection(connection.Key, connection.Value));
        }
        catch (Exception e)
        {
            // Get System.Net.Sockets.SocketException (0x80004005): An established connection was aborted by the software in your host machine here!!!
            connToRemove.Add(connection.Key);
        }
    }
    // Close broken connections
    foreach (var endPoint in connToRemove)
    {
        CloseSocket(endPoint);
    }
}

private void SendCallback(IAsyncResult result)
{
    var connection = (ClientConnection)result.AsyncState;
    try
    {
        connection.Sock.EndSend(result);
    }
    catch (Exception e)
    {
        CloseSocket(connection.RemoteEndPoint);
    }
}

private void CloseSocket(EndPoint endPoint)
{
    Socket socketToClose;
    _clientConnections.TryGetValue(endPoint, out socketToClose)
    try
    {
        socketToClose.Close();
        socketToClose.Dispose();
    }
    catch (Exception e)
    {
        Logger.Error("Error of closing/disposing socket.", e);
    }
    finally
    {
        Socket removable;
        if (!_clientConnections.TryRemove(endPoint, out removable))
        {
            Logger.Warn("Can not remove an endPoint ({0}) from the client-connections-dict ({1}).",
                endPoint, string.Join(", ", _clientConnections.Keys));
        }
    }
}

Now I get an exception

System.Net.Sockets.SocketException (0x80004005): An established connection was aborted by the software in your host machine

when call BeginSend among 20-50 successful sent. What I've noticed is that exception always throws soon after new connection accepted:

TRACE 674 bytes successfully sent to client 212.193.xxx.xxx:21666
TRACE 674 bytes successfully sent to client 212.193.xxx.xxx:21666
DEBUG An endPoint (212.193.xxx.xxx:22014) successfully added to the client-connections-dict (212.193.xxx.xxx:21666, 212.193.xxx.xxx:22014) 
TRACE 674 bytes successfully sent to client 212.193.xxx.xxx:21666 
TRACE 674 bytes successfully sent to client 212.193.xxx.xxx:22014 
WARN Closing socket 212.193.xxx.xxx:21666 because of exception while BeginSend: System.Net.Sockets.SocketException (0x80004005): An established connection was aborted by the software in your host machine

But I don't know why the error occurs and how to fix it. Please help!

EDIT: I've sniffed the traffic and found out that one of clients (who always was a source of problems) periodically sends tcp packet with a Reset flag. That's why I failed to send packet to it. According to this answer this may may occure because of server received packet for a closed socket. I wonder why this may happen and how server should behave in this situation.

Community
  • 1
  • 1
Zharro
  • 819
  • 1
  • 11
  • 23
  • What is `CloseSocket`? (To close a `Socket` call its `Close` method or dispose of it, using an `EndPoint` for this seems very strange.) – Richard Jan 22 '15 at 15:00
  • @Richard see my updare. – Zharro Jan 22 '15 at 15:09
  • Without a complete code example (you don't even show enough code to support the output you claim to get), it will be impossible to provide any specific advice. The message you are getting corresponds to the Winsock error `WSAECONNABORTED`, which can happen for a variety of reasons. You may want to search the web for information about that error. – Peter Duniho Jan 22 '15 at 20:01

0 Answers0