Cannot use breakpoint in the callback function of Socket.BeginConnect()

    public bool Connect (string address, int remotePort)
    {
        if (_socket != null && _socket.Connected)
            return true;


        IPHostEntry hostEntry = Dns.GetHostEntry (address);
        foreach (IPAddress ip in hostEntry.AddressList) {
            try {
                IPEndPoint ipe = new IPEndPoint (ip, remotePort);

                _socket = new Socket (ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                _socket.BeginConnect (ipe, new System.AsyncCallback (ConnectionCallback), _socket);

                break;

            } catch (System.Exception e) {
                PushPacket ((ushort)MsgIds.Id.CONNECTION_ATTEMPT_FAILED, e.Message);
                return false;
            }

        }

        return true;
    }

    void ConnectionCallback (System.IAsyncResult ar)
    {
        NetBitStream stream = new NetBitStream ();

        stream._socket = (Socket)ar.AsyncState;

        try {
            _socket.EndConnect (ar);

            _socket.SendTimeout = _sendTimeout;
            _socket.ReceiveTimeout = _revTimeout;

            PushPacket ((ushort)MsgIds.Id.CONNECTION_REQUEST_ACCEPTED, "");

            _socket.BeginReceive (stream.BYTES, 0, NetBitStream.HEADER_LENGTH, SocketFlags.None, new System.AsyncCallback (ReceiveHeader), stream);


        } catch (System.Exception e) {
            if (e.GetType () == typeof(SocketException)) {
                if (((SocketException)e).SocketErrorCode == SocketError.ConnectionRefused) {
                    PushPacket ((ushort)MsgIds.Id.CONNECTION_ATTEMPT_FAILED, e.Message);
                } else
                    PushPacket ((ushort)MsgIds.Id.CONNECTION_LOST, e.Message);
            }

            Disconnect (0);
        }
    }

Here are two functions. When I call

client.Connect ("127.0.0.1", 10001);

It just steps over the break; after

  _socket.BeginConnect (ipe, new System.AsyncCallback (ConnectionCallback), _socket);

and goes to return true;. I set a breakpoint at ConnectionCallback but it does not go into this function.

There is no server listening on the 10001 port.

So I think it at least should throw an exception (connect failed), then go into the catch.

Or have I made a mistake in the two functions?

Here is a Minimal, Complete, and Verifiable example

    using System;
using System.Net.Sockets;
using System.Net;

namespace TestSocket
{
    class MainClass
    {
        public static void Main (string[] args)
        {
            NetTCPClient tcp_client = new NetTCPClient ();
            tcp_client.Connect ("127.0.0.1", 10001);
        }
    }

    class NetTCPClient
    {
        Socket _socket = null;
        public bool Connect (string address, int remote_port)
        {
            if (_socket != null && _socket.Connected)
                return true;
            IPHostEntry host_entry = Dns.GetHostEntry (address);
            foreach (IPAddress ip in host_entry.AddressList) {
                try {
                    IPEndPoint ipe = new IPEndPoint (ip, remote_port);
                    _socket = new Socket (ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                    IAsyncResult ia = _socket.BeginConnect (ipe, new System.AsyncCallback (ConnectionCallback), _socket);
                    break;
                } catch (Exception e) {
                    Console.WriteLine ("Connet() catch an exception!");
                    return false;
                }
            }
            return true;
        }

        void ConnectionCallback (System.IAsyncResult ar)
        {
            Console.WriteLine ("ConnectionCallback() ");
        }

    }

}
Jon Skeet
people
quotationmark

I think you may have misunderstood what BeginConnect does. That doesn't make the connection - it just starts making the connection, asynchronously. So yes, I'm not at all surprised that "step over" immediately steps to the next statement - that's working as intended.

However, I would have expected that a breakpoint in ConnectionCallback would be hit - that's what you should concentrate on as a problem. That's also where you should put the exception handling, as that's where any problems with making the connection would be found.

Alternatively, if you're using C# 5 or higher, you should look into using async/await, which would allow you to get rid of all the callbacks. Then you'll get a much more familiar experience when debugging - if you step over that line, it really will be connected (or there'll be a failure) by the time you hit the next line. Just be aware that other things may happen (even on the same thread) while it's "awaiting" the response.

Unfortunately, I can't see anything in Socket which implements the relevant pattern. You could use TaskFactory.FromAsync to adapt the "old" style to the "new" style, but it's likely to be fairly painful.

Another approach is to try to move to higher-level constructs like TcpClient instead of the lower-level Socket class.

people

See more on this question at Stackoverflow