Skip to main content
Bumped by Community user
Bumped by Community user
Bumped by Community user
Bumped by Community user
Tweeted twitter.com/StackCodeReview/status/917490001138667520
added 907 characters in body
Source Link
Walt Byers
  • 131
  • 1
  • 7

EDIT: Maybe I'll highlight some parts I'm concerned about. Am I doing the Task.Factory.FromAsync right? Especially for ReceiveAsync and SendAsync? I saw a strange example that looked like this:

  var revcLen = await Task.Factory.FromAsync(
                     (cb, s) => clientSocket.BeginReceive(prefix, 0, prefix.Length, SocketFlags.None, cb, s),
                     ias => clientSocket.EndReceive(ias),
                     null);

Why the extra lambda expression? It seems like they are just forcing the usage of one overload while another would be better suited.

Also, do you guys think I should just return zero bytes from ReceiveAsync instead of throwing ConnectionClosedException? Then I can just let the exceptions flow from the socket methods and wrap them in a higher layer. I have a connection abstraction that handles message framing and eventually keep alives.

EDIT: Maybe I'll highlight some parts I'm concerned about. Am I doing the Task.Factory.FromAsync right? Especially for ReceiveAsync and SendAsync? I saw a strange example that looked like this:

  var revcLen = await Task.Factory.FromAsync(
                     (cb, s) => clientSocket.BeginReceive(prefix, 0, prefix.Length, SocketFlags.None, cb, s),
                     ias => clientSocket.EndReceive(ias),
                     null);

Why the extra lambda expression? It seems like they are just forcing the usage of one overload while another would be better suited.

Also, do you guys think I should just return zero bytes from ReceiveAsync instead of throwing ConnectionClosedException? Then I can just let the exceptions flow from the socket methods and wrap them in a higher layer. I have a connection abstraction that handles message framing and eventually keep alives.

Source Link
Walt Byers
  • 131
  • 1
  • 7

C# Async Socket Wrapper

I'd like to get a little feedback on this async socket wrapper. My goal is to merge socket Begin/End methods into a single async call. I also wanted to wrap exceptions so they are easier to handle in others areas of my program. Any red flags? Any potential problems? I know its not doing much but I want to get this right.

public class SimpleSocket
{
    private readonly Socket _socket;

    public SimpleSocket()
    {
        _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    }

    public SimpleSocket(Socket socket)
    {
        _socket = socket;
    }

    public void Bind(int port)
    {
        var endPoint = new IPEndPoint(IPAddress.Any, port);

        try
        {
            _socket.Bind(endPoint);
        }
        catch (Exception e)
        {
            throw new ConnectionErrorException($"Failed to bind to {port}", e);
        }
    }

    public void Listen(int backlog)
    {
        try
        {
            _socket.Listen(backlog);
        }
        catch (Exception e)
        {
            throw new ConnectionErrorException($"Failed to listen with backlog of {backlog}", e);
        }
    }

    public async Task<SimpleSocket> AcceptAsync()
    {
        Socket socket;

        try
        {
            socket = await Task.Factory.FromAsync(_socket.BeginAccept, _socket.EndAccept, true);
        }
        catch (Exception e)
        {
            throw new ConnectionErrorException("Failed to accept connection", e);
        }

        return new SimpleSocket(socket);
    }

    public async Task ConnectAsync(string host, int port)
    {
        try
        {
            await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, host, port, null);
        }
        catch (Exception e)
        {
            throw new ConnectionErrorException($"Failed to connect to {host}:{port}", e);
        }
    }

    public async Task<int> ReceiveAsync(byte[] buffer, int offset, int size)
    {
        int bytesReceived;

        try
        {
            bytesReceived = await Task<int>.Factory.FromAsync(
                _socket.BeginReceive(buffer, offset, size, SocketFlags.None, null, null),
                _socket.EndReceive);
        }
        catch (Exception e)
        {
            if (e is SocketException se && se.SocketErrorCode == SocketError.ConnectionReset)
            {
                throw new ConnectionClosedException("Connection reset");
            }

            throw new ConnectionErrorException("Failed to receieve message", e);
        }

        if (bytesReceived == 0)
        {
            throw new ConnectionClosedException("Connection closed");
        }

        return bytesReceived;
    }

    public async Task<int> SendAsync(byte[] buffer, int offset, int size)
    {
        try
        {
            return await Task<int>.Factory.FromAsync(
                _socket.BeginSend(buffer, offset, size, SocketFlags.None, null, null),
                _socket.EndSend);
        }
        catch (Exception e)
        {
            throw new ConnectionErrorException("Failed to send message", e);
        }
    }

    public void Close()
    {
        _socket.Close();
    }
}