C# Socket BeginConnect // CallBackMethod

Markus Freitag 3,791 Reputation points
2023-02-09T18:51:24.4633333+00:00

My analysis is that the callback is called immediately whether there is a connection or not.

This is the reason why the behavior I expect does not occur.

So I had a misunderstanding of the function.

var result = socket.BeginConnect(remoteEndPoint, CallBackMethod, socket);

I want to press Connect and then give the client 60 seconds to connect. That is the goal.

Does anyone have an idea how to do this correctly? By BeginConnect I thought that this is asynchronous. When do I need EndConnect? Do I need a timer, then yes asynchronous is not needed.

public void Connect(IPEndPoint remoteEndPoint, int timeoutMSec)
{
	//socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
	//socket.Blocking = true;

	//var result = socket.BeginConnect(remoteEndPoint, null, null);

	//bool success = result.AsyncWaitHandle.WaitOne(125000, true);
	//if (success)
	//{
	//    socket.EndConnect(result);
	//    //_connectionStatus = ConnectionStatus.Connected;
	//    //_connectionStatusMessage = "Connected.";
	//}
	//else
	//{
	//    socket.Close();
	//    //_connectionStatus = ConnectionStatus.Error;
	//    //_connectionStatusMessage = "Connection timed out.";
	//}
	TimeoutObject.Reset();
	socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
	var result = socket.BeginConnect(remoteEndPoint, CallBackMethod, socket);

	WaitHandle wait = result.AsyncWaitHandle;

	//block the current thread        
	//if (TimeoutObject.WaitOne(timeoutMSec, false))
	if (wait.WaitOne(timeoutMSec))
	//if (!TimeoutObject.WaitOne(timeoutMSec, false))
	{
		Log("Port is ok");
		Thread th = new Thread(receive);
		th.IsBackground = true;
		th.Start();
	}
	else
	{
		Log("timeout");
	}
}
//--asynchronous callback method   
private void CallBackMethod(IAsyncResult asyncresult)
{
	//Make a blocked thread continue      
	//TimeoutObject.Set();


	TimeoutObject.Set();
	Socket s = (Socket)asyncresult.AsyncState;
	if (s.Connected)
	{
		// Success...should EndConnect only be called here?
		s.EndConnect(asyncresult);
	}
	else
	{
		// Or should EndConnect also be called here (in a try/catch block)?
		s.Close();
	}
}
Developer technologies | .NET | Other
Developer technologies | C#
0 comments No comments
{count} votes

Accepted answer
  1. Michael Taylor 60,161 Reputation points
    2023-02-09T19:17:26.2+00:00

    BeginConnect is an async call. When you call that method it returns immediately so the caller isn't blocked. Behind the scenes a connection is made to the remote server. As soon as the handshaking is done then your callback is called to let you know you now have a connection to the remote endpoint. In many cases this should be really fast but if the server is slow to respond or the network is swamped then it could take a little longer. The purpose of this method is to allow your code to move on and do other things while waiting (such as displaying a connecting message to the user).

    When the callback gets called you need to call EndConnect. Every Begin... method has a corresponding End... method. The Begin call has to allocate resources for the async callback. The End call tells the runtime that those resources can be cleaned up. If you don't call this method then you end up leaking the resources that were allocated. You just need to call it at some point during your callback. Most people tend to call this early in the callback in case the callback fails.

    Note that you should really never be using the Begin/End methods. These are provided for backwards compatibility and to provide a thin wrapper over the underlying winsock library that supports async. This is how async used to work. For current code you should be using the ConnectAsync method instead. Task-based async is the preferred approach in all cases now. It requires less code and it just works. The equivalent code would look something like this.

    async void ConnectAsync (...)
    {
       await socket.ConnectAsync(...);
    
       //Connected so do real work now
    }
    

    It looks like you want to give up if you cannot connect within 30 seconds. You can do that by passing a CancellationToken that auto-cancels after 30 seconds.

    async void ConnectAsync (...)
    {
       var cancel = new CancellationTokenSource(TimeSpan.FromSeconds(30));
       try
       {
          await socket.ConnectAsync(..., cancel.Token);
    
          //Connected, do real work
       } catch (OperationCanceledException)   
       {
          //Connection was cancelled
       };
    }
    

1 additional answer

Sort by: Most helpful
  1. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.