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);
}
}
这是两个功能。当我打电话
client.Connect ("127.0.0.1", 10001);
它只是在{/ 1}之后跳过
break;
然后转到 _socket.BeginConnect (ipe, new System.AsyncCallback (ConnectionCallback), _socket);
。我在ConnectionCallback上设置了一个断点,但它没有进入这个函数。
return true;
端口上没有服务器监听。
所以我认为它至少应该抛出异常(连接失败),然后进入10001
。
或者我在这两个函数中犯了错误?
这是一个最小的,完整的,可验证的例子
catch
答案 0 :(得分:2)
我想你可能误解了BeginConnect
的作用。这不会建立连接 - 它只是启动以异步方式建立连接。所以是的,我并不感到惊讶的是,“跳过”会立即进入下一个声明 - 这是按预期工作的。
然而,我 预计ConnectionCallback
中的断点会被击中 - 这就是你应该把注意力集中在一个问题上。这也是你应该进行异常处理的地方,因为这样就可以找到任何连接问题。
或者,如果你使用的是C#5或更高版本,你应该考虑使用async / await,它可以让你摆脱所有的回调。然后你会在调试时获得更熟悉的体验 - 如果你跨过那条行,它就会在你到达下一行时被连接(或者会出现故障)。请注意,在“等待”响应时,可能会发生其他事情(即使在同一个线程上)。
不幸的是,我在Socket
中看不到任何实现相关模式的内容。您可以使用TaskFactory.FromAsync
使“旧”风格适应“新”风格,但这可能会非常痛苦。
另一种方法是尝试转移到更高级别的结构,例如TcpClient
而不是更低级别的Socket
类。
答案 1 :(得分:2)
调试器不会那样工作。除了极少数例外,如果没有您的明确指示,它将不会切换线程。
当您逐步执行您编写的Connect()
方法时,您正在调试程序中的特定线程。 ConnectionCallback()
方法,如果调用它(请注意,在调用BeginConnect()
期间通常会同步调用 ),将以不同的方式调用线。如果要调试它,则需要在ConnectionCallback()
方法本身或其中设置断点。
在该方法中设置断点后,无论哪个线程正在执行该方法,您都可以确保调试器将暂停程序的执行。
修改强>
感谢您提供完整的代码示例。假设 实际上是您正在测试并遇到问题的代码示例,那么您的问题(正如已经猜到的那样)是两件事之一:
Connect()
方法后,您不会继续执行您的程序。即你没有点击"继续"按钮或使用"继续" " Debug"中的菜单项菜单。或... 如果上面的情况#1,您永远不会看到断点,因为您的程序没有执行。只有在程序执行确实到达断点时才能触发断点。但是如果你的程序没有发生,那么你的程序的执行就无法到达那里。
在上面的情况#2中,您永远不会看到断点,因为您的程序没有执行。在这种情况下,它是因为该程序完全退出。
如果你想看到触发ConnectionCallback()
方法的断点,你需要让程序运行,并且足够长时间才能实现。
作为一个快速概念验证,我在该方法中设置了一个断点,并将此语句添加到Main()
方法的末尾:
Thread.Sleep(TimeSpan.FromMinutes(5));
然后我使用调试器逐步执行Main()
方法。它当然暂停让程序在我刚刚添加的上述语句中运行,但是然后很快就在所需的断点处再次中断了程序。 (我没有等到接近5分钟的时间......我只是把它当作一个非常大的时间值,我确信这已经足够了。)
为了它的价值,我还尝试了一个测试,我逐步完成原始的Main()
,即没有调用Thread.Sleep()
,但在踩过调用后等待大约5-10秒在继续之前Connect()
。在这种情况下,至少在我的计算机上,我也确实看到了断点被触发。该特定测试在某种程度上取决于机器配置,因此它不如将调用添加到Thread.Sleep()
那样可靠。但它确实适用于我的情况。