不能在Socket.BeginConnect()的回调函数中使用断点
本文关键字:函数 断点 回调 Socket BeginConnect 不能 | 更新日期: 2023-09-27 17:49:36
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);
它会跳过
后面的break;
_socket.BeginConnect (ipe, new System.AsyncCallback (ConnectionCallback), _socket);
转到return true;
。我在ConnectionCallback设置了一个断点,但它没有进入这个函数。
10001
端口没有服务器监听。
所以我认为它至少应该抛出一个异常(连接失败),然后进入catch
。
还是我在两个函数中犯了错误?
这是一个最小的,完整的,可验证的例子
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() ");
}
}
}
调试器不是这样工作的。除了极少数例外,它不会在没有你的明确指令的情况下切换线程。
当您逐步执行您编写的Connect()
方法时,您正在调试程序中的特定线程。ConnectionCallback()
方法,如果它被调用(注意它是而不是通常将在调用BeginConnect()
期间被同步调用),将在不同的线程中被调用。如果你想调试它,你需要在ConnectionCallback()
方法本身设置一个断点。
如果在该方法中设置了断点,则可以确保调试器将在那里暂停程序的执行,而不管哪个线程正在执行该方法。
编辑:感谢您的完整代码示例。假设实际上就是您正在测试并遇到问题的代码示例,那么您的问题是(正如已经猜到的)以下两种情况之一:
- 在逐步完成对
Connect()
方法的调用之后,您不恢复程序的执行。也就是说,您没有点击"继续"按钮或使用"调试"菜单中的"继续"菜单项。Or… - 你继续执行你的程序,然后在连接尝试被解决之前迅速退出。
如果您想看到ConnectionCallback()
方法的断点被触发,您需要让程序运行,并且运行足够长的时间。
Main()
方法的末尾:
Thread.Sleep(TimeSpan.FromMinutes(5));
然后我使用调试器逐步通过Main()
方法。它当然会暂停,让程序在我刚刚添加的语句处运行,但随后又很快在所需的断点处再次中断程序。(我不需要等待近5分钟& help;我只是把它作为一个非常大的时间值,我确信这是足够的)。
为了它的价值,我还尝试了一个测试,我跳过了原始的Main()
,即没有调用Thread.Sleep()
,但在继续之前跳过对Connect()
的调用后等待大约5-10秒。在这种情况下,至少在我的计算机上,我也确实看到了断点被触发。这个特定的测试在某种程度上依赖于机器配置,因此它不如将调用添加到Thread.Sleep()
可靠。
我想你可能误解了BeginConnect
的作用。这不会建立连接——它只是开始异步地建立连接。所以,是的,我一点也不惊讶"step over"会立即跳到下一个语句——这是预期的效果。
然而,我将期望ConnectionCallback
中的断点将被击中-这是您应该关注的问题。这也是您应该放置异常处理的地方,因为在那里可以发现建立连接的任何问题。
或者,如果你正在使用c# 5或更高版本,你应该考虑使用async/await,这将允许你摆脱所有的回调。然后,在调试时,您将获得更加熟悉的体验—如果您跳过那行,那么在您到达下一行时,它确实将被连接(或者将出现故障)。只是要注意,当它"等待"响应时,可能会发生其他事情(即使在同一个线程上)。
不幸的是,我在Socket
中看不到任何实现相关模式的东西。您可以使用TaskFactory.FromAsync
将"旧"样式调整为"新"样式,但这可能相当痛苦。
另一种方法是尝试移动到更高级的结构,如TcpClient
,而不是较低级别的Socket
类。