-1

I'm trying to better understand C# Socket classes. I'm working with a TcpClient object. I'm using it into a Unity (game development) project, so I cannot block the main thread. I would like to use method with Begin/End form like, for example, BeginConnect() and EndConnect().

I'm doing this:

public class TcpTest : MonoBehaviour
{
     private TcpClient m_TcpClient = null;

     private void Start()
     {
          m_TcpClient = new TcpClient();
          m_TcpClient.BeginConnect("127.0.0.1", 40000, OnConnectAsyncCallback, null);
     }

     private void OnConnectAsyncCallback(IAsyncResult i_AsyncResult)
     {
          m_TcpClient.EndConnect(i_AsyncResult);

          MyAsyncDebug.Log("Connect callback received.");
     }
}

I'm using hercules as a socket debugging tool. I've started a TCP server with it and everythings was fine. Then I've stopped the TCP server on hercules. I've re-ran my code and I was expecting an error or an exception. Nothing, the code just starts the BeginConnect() and the AsyncCallback is never called anymore. I've also tried to start the server after the BeginConnect method was called but it does not work.

How can I know if Begin Connect is failed (maybe the destination is unreachable or any other reason)?

I cannot understand how they are designed (I've already read the MSDN docs).

Thank you and sorry for the newbie question!

erre
  • 39
  • 2
  • 6
  • BeginConnect makes the tcpClient try to connect to server on a pool thread. When the connection is established, the Callback is fired and you call EndConnect. From here onwards you can GetStream() for the tcpClient and do Read/BeginRead or Write/BeginWrite – Prateek Shrivastava Mar 09 '20 at 20:54
  • To know if the BeginConnect was sucessful or not, check TcpClient.Connected property in the callback. – Prateek Shrivastava Mar 09 '20 at 20:56
  • Thanks for help @PrateekShrivastava! My problem is that the callback is not called if the 'server' is not present (if I don't open the listener with Hercules). So I cannot check the property! My question was: "Why I don't receive the callback in these cases?" – erre Mar 09 '20 at 21:12
  • Network questions are hard enough to answer, and very often off-topic, even when a good [mcve] is presented. But here, there's not nearly enough information. That said: _"the callback is not called if the 'server' is not present"_ -- after you call `BeginConnect()` your callback will definitely be called eventually. It will take a lot longer, because you have to wait for the connection attempt to timeout. But eventually it will, and the call to `EndConnect()` will throw an exception indicating that error. – Peter Duniho Mar 09 '20 at 22:54
  • Thanks @PeterDuniho! What you say is exaclty what I want! What is the default timeout for the BeginConnect()? Because I've waited very long but the callback is never called (this is the reason I posted this question here). Eventually, do you know a way to set the timeout? Thank you – erre Mar 09 '20 at 23:33
  • I don't recall the default off the top of my head. It's on the order of minutes though (probably somewhere between one and three). It is possible to change the default, but IMHO that's counterproductive. TCP's defaults have been designed and tested over the years to be forgiving of less-than-optimal connections. Shortening the timeout will cause errors to happen when they otherwise could be avoided. Consider including in your UI a button the user can use to cancel the connection attempt; in code you'd just close the socket, which would cause the connection attempt to complete with an exception – Peter Duniho Mar 10 '20 at 00:58
  • This application will works just in a LAN. I'm doing this just to handle a server crash (automatically reconnecting to it). Default TCP tuning is perfect for Internet maybe, but in this situation a smaller timeout would be great. I can't find in the documentation anything about the default timeout and how to change it? Do you know where I can find the docs? – erre Mar 10 '20 at 08:14

1 Answers1

0

TcpClient does not have a property to set connection time out. There are properties for send and receive timeout but not connection timeout. One common way of waiting for connection timeout is to wait on the IAsyncResult from BeginConnect or use the ConnectAsync

IAsyncResult ar = client.BeginConnect("host", port, null, null);
var success = ar.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(60));

OR

var client = new TcpClient();
if (!client.ConnectAsync("host", port).Wait(60))

Once timeout you have to close the client. In your original code the callback should eventually get called.

PraveenB
  • 1,270
  • 10
  • 11
  • Thanks. "Once timeout you have to close the client. In your original code the callback should eventually get called." This is the problem, my callback does not get called.. It just works if the server is online and accept the connection. If I don't start the server, nothing happen. Maybe I can try to do something with the Task returned by the ConnectAsync, but I'm just confused about the BeginConnect() strange behavior. Thank you. – erre Mar 11 '20 at 13:28
  • How are you checking that your callback is not called ? Is it just that one log ? How are you waiting for it to come back ? If you could post some more code on how are you waiting for it ? A simple code with your client without Unity and give invalid host/port. tcp.start(); Thread.Sleep(2000); – PraveenB Mar 11 '20 at 16:15
  • You will see that callback is called within few seconds. – PraveenB Mar 11 '20 at 16:15